diff options
Diffstat (limited to 'plugins')
549 files changed, 50599 insertions, 8580 deletions
diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 8d39c37..1cda6e0 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -5,6 +5,12 @@ PYTHON3_SUBDIRS = pychrysalide python endif +if BUILD_GTK_SUPPORT + +ROPGADGETS_SUBDIRS = ropgadgets + +endif + # androhelpers SUBDIRS = \ $(PYTHON3_SUBDIRS) \ @@ -18,15 +24,18 @@ SUBDIRS = \ fmtp \ itanium \ javadesc \ + kaitai \ mobicore \ pe \ yaml \ + apihashing \ bhash \ dalvik \ + encodings \ libcsem \ lnxsyscalls \ readdex \ readelf \ readmc \ - ropgadgets \ + $(ROPGADGETS_SUBDIRS) \ winordinals diff --git a/plugins/apihashing/Makefile.am b/plugins/apihashing/Makefile.am new file mode 100644 index 0000000..d73f8b0 --- /dev/null +++ b/plugins/apihashing/Makefile.am @@ -0,0 +1,65 @@ + +lib_LTLIBRARIES = libapihashing.la + +libdir = $(pluginslibdir) + + +if BUILD_PYTHON_PACKAGE + +RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs:$$ORIGIN' + +else + +RUN_PATH = -Wl,-rpath,'$$ORIGIN' + +endif + +if BUILD_PYTHON3_BINDINGS + +PYTHON3_LIBADD = python/libapihashingpython.la + +if BUILD_DISCARD_LOCAL + +if BUILD_PYTHON_PACKAGE +PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN/..' +else +PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN' +endif + +else + +PYTHON3_RUN_PATH = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs + +endif + +PYTHON3_LDFLAGS = $(PYTHON3_RUN_PATH) -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so + +PYTHON3_SUBDIRS = python + +endif + + +libapihashing_la_SOURCES = \ + apihash.h apihash.c \ + core.h core.c + +libapihashing_la_LIBADD = \ + $(PYTHON3_LIBADD) \ + classics/libapihashingclassics.la \ + custom/libapihashingcustom.la + +libapihashing_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + +libapihashing_la_LDFLAGS = \ + -avoid-version \ + -L$(top_srcdir)/src/.libs -lchrysacore \ + -L$(top_srcdir)/plugins/pe/.libs -lpe \ + $(RUN_PATH) $(PYTHON3_LDFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libapihashing_la_SOURCES:%c=) + + +SUBDIRS = $(PYTHON3_SUBDIRS) classics custom diff --git a/plugins/apihashing/apihash.c b/plugins/apihashing/apihash.c new file mode 100644 index 0000000..3313073 --- /dev/null +++ b/plugins/apihashing/apihash.c @@ -0,0 +1,134 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * apihash.c - détermination d'API par empreinte de fonction + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "apihash.h" + + +#include <analysis/scan/patterns/modifier-int.h> + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en empreintes d'API. */ +static void g_api_hash_modifier_class_init(GApiHashModifierClass *klass); + +/* Initialise une instance de transmission en empreinte d'API. */ +static void g_api_hash_modifier_init(GApiHashModifier *); + +/* Supprime toutes les références externes. */ +static void g_api_hash_modifier_dispose(GApiHashModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_api_hash_modifier_finalize(GApiHashModifier *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte d'API. */ +G_DEFINE_TYPE(GApiHashModifier, g_api_hash_modifier, G_TYPE_SCAN_TOKEN_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en empreintes d'API. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_api_hash_modifier_class_init(GApiHashModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_api_hash_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_api_hash_modifier_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en empreinte d'API. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_api_hash_modifier_init(GApiHashModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_api_hash_modifier_dispose(GApiHashModifier *modifier) +{ + G_OBJECT_CLASS(g_api_hash_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_api_hash_modifier_finalize(GApiHashModifier *modifier) +{ + G_OBJECT_CLASS(g_api_hash_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} diff --git a/plugins/apihashing/apihash.h b/plugins/apihashing/apihash.h new file mode 100644 index 0000000..cfc3365 --- /dev/null +++ b/plugins/apihashing/apihash.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * apihash.h - prototypes pour la détermination d'API par empreinte de fonction + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_APIHASH_H +#define _PLUGINS_APIHASHING_APIHASH_H + + +#include <glib-object.h> + + +#include <analysis/scan/patterns/modifier.h> + + + +#define G_TYPE_API_HASH_MODIFIER g_api_hash_modifier_get_type() +#define G_API_HASH_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_API_HASH_MODIFIER, GApiHashModifier)) +#define G_IS_API_HASH_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_API_HASH_MODIFIER)) +#define G_API_HASH_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_API_HASH_MODIFIER, GApiHashModifierClass)) +#define G_IS_API_HASH_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_API_HASH_MODIFIER)) +#define G_API_HASH_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_API_HASH_MODIFIER, GApiHashModifierClass)) + + +/* Transormation en empreinte d'API (instance) */ +typedef GScanTokenModifier GApiHashModifier; + +/* Transormation en empreinte d'API (classe) */ +typedef GScanTokenModifierClass GApiHashModifierClass; + + +/* Indique le type défini pour une transormation en empreinte d'API. */ +GType g_api_hash_modifier_get_type(void); + + + +#endif /* _PLUGINS_APIHASHING_APIHASH_H */ diff --git a/plugins/apihashing/classics/Makefile.am b/plugins/apihashing/classics/Makefile.am new file mode 100644 index 0000000..9f97b47 --- /dev/null +++ b/plugins/apihashing/classics/Makefile.am @@ -0,0 +1,14 @@ + +noinst_LTLIBRARIES = libapihashingclassics.la + +libapihashingclassics_la_SOURCES = \ + crc32.h crc32.c \ + djb2.h djb2.c \ + ror13.h ror13.c + +libapihashingclassics_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libapihashingclassics_la_SOURCES:%c=) diff --git a/plugins/apihashing/classics/crc32.c b/plugins/apihashing/classics/crc32.c new file mode 100644 index 0000000..98f9a6b --- /dev/null +++ b/plugins/apihashing/classics/crc32.c @@ -0,0 +1,332 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * crc32.c - transormation en empreinte d'API crc32 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "crc32.h" + + +#include <malloc.h> +#include <string.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en empreintes crc32. */ +static void g_scan_crc32_modifier_class_init(GScanCrc32ModifierClass *klass); + +/* Initialise une instance de transmission en empreinte crc32. */ +static void g_scan_crc32_modifier_init(GScanCrc32Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_crc32_modifier_dispose(GScanCrc32Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_crc32_modifier_finalize(GScanCrc32Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_crc32_modifier_get_name(const GScanCrc32Modifier *); + +/* Calcule l'empreinte crc32 d'un motif de recherche. */ +static uint32_t compute_crc32(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_crc32_modifier_transform(const GScanCrc32Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_crc32_modifier_get_path(const GScanCrc32Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en encodage Crc32. */ +G_DEFINE_TYPE(GScanCrc32Modifier, g_scan_crc32_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en empreintes crc32. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_crc32_modifier_class_init(GScanCrc32ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_crc32_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_crc32_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_crc32_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_crc32_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_crc32_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en empreinte crc32. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_crc32_modifier_init(GScanCrc32Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_crc32_modifier_dispose(GScanCrc32Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_crc32_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_crc32_modifier_finalize(GScanCrc32Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_crc32_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des empreintes crc32. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_crc32_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_CRC32_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_crc32_modifier_get_name(const GScanCrc32Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("crc32"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte crc32 d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_crc32(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t i; /* Boucle de parcours #1 */ + size_t k; /* Boucle de parcours #2 */ + + result = 0xffffffff; + + for (i = 0; i < src->len; i++) + { + result ^= src->data[i]; + + for (k = 0; k < 8; k++) + result = result & 1 ? (result >> 1) ^ 0xedb88320 : result >> 1; + + } + + result = ~result; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_crc32_modifier_transform(const GScanCrc32Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_crc32(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_crc32_modifier_get_path(const GScanCrc32Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("crc32"); + + return result; + +} diff --git a/plugins/apihashing/classics/crc32.h b/plugins/apihashing/classics/crc32.h new file mode 100644 index 0000000..0198c5d --- /dev/null +++ b/plugins/apihashing/classics/crc32.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * crc32.h - prototypes pour la transormation en empreinte d'API crc32 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CLASSICS_CRC32_H +#define _PLUGINS_APIHASHING_CLASSICS_CRC32_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_CRC32_MODIFIER g_scan_crc32_modifier_get_type() +#define G_SCAN_CRC32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_CRC32_MODIFIER, GScanCrc32Modifier)) +#define G_IS_SCAN_CRC32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_CRC32_MODIFIER)) +#define G_SCAN_CRC32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_CRC32_MODIFIER, GScanCrc32ModifierClass)) +#define G_IS_SCAN_CRC32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_CRC32_MODIFIER)) +#define G_SCAN_CRC32_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_CRC32_MODIFIER, GScanCrc32ModifierClass)) + + +/* Transormation en empreinte d'API crc32 (instance) */ +typedef GApiHashModifier GScanCrc32Modifier; + +/* Transormation en empreinte d'API crc32 (classe) */ +typedef GApiHashModifierClass GScanCrc32ModifierClass; + + +/* Indique le type défini pour une transormation en empreinte crc32. */ +GType g_scan_crc32_modifier_get_type(void); + +/* Construit un modificateur livrant des empreintes crc32. */ +GScanTokenModifier *g_scan_crc32_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CLASSICS_CRC32_H */ diff --git a/plugins/apihashing/classics/djb2.c b/plugins/apihashing/classics/djb2.c new file mode 100644 index 0000000..524218f --- /dev/null +++ b/plugins/apihashing/classics/djb2.c @@ -0,0 +1,323 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * djb2.c - transormation en empreinte d'API djb2 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "djb2.h" + + +#include <malloc.h> +#include <string.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en empreintes djb2. */ +static void g_scan_djb2_modifier_class_init(GScanDjb2ModifierClass *klass); + +/* Initialise une instance de transmission en empreinte djb2. */ +static void g_scan_djb2_modifier_init(GScanDjb2Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_djb2_modifier_dispose(GScanDjb2Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_djb2_modifier_finalize(GScanDjb2Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_djb2_modifier_get_name(const GScanDjb2Modifier *); + +/* Calcule l'empreinte djb2 d'un motif de recherche. */ +static uint32_t compute_djb2(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_djb2_modifier_transform(const GScanDjb2Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_djb2_modifier_get_path(const GScanDjb2Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en encodage Djb2. */ +G_DEFINE_TYPE(GScanDjb2Modifier, g_scan_djb2_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en empreintes djb2. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_djb2_modifier_class_init(GScanDjb2ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_djb2_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_djb2_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_djb2_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_djb2_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_djb2_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en empreinte djb2. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_djb2_modifier_init(GScanDjb2Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_djb2_modifier_dispose(GScanDjb2Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_djb2_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_djb2_modifier_finalize(GScanDjb2Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_djb2_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des empreintes djb2. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_djb2_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_DJB2_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_djb2_modifier_get_name(const GScanDjb2Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("djb2"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte djb2 d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_djb2(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t i; /* Boucle de parcours */ + + result = 0x1505; /* 5381 */ + + for (i = 0; i < src->len; i++) + result = ((result << 5) + result) + src->data[i]; /* hash * 33 + c */ + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_djb2_modifier_transform(const GScanDjb2Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_djb2(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_djb2_modifier_get_path(const GScanDjb2Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("djb2"); + + return result; + +} diff --git a/plugins/apihashing/classics/djb2.h b/plugins/apihashing/classics/djb2.h new file mode 100644 index 0000000..04df1df --- /dev/null +++ b/plugins/apihashing/classics/djb2.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * djb2.h - prototypes pour la transormation en empreinte d'API djb2 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CLASSICS_DJB2_H +#define _PLUGINS_APIHASHING_CLASSICS_DJB2_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_DJB2_MODIFIER g_scan_djb2_modifier_get_type() +#define G_SCAN_DJB2_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_DJB2_MODIFIER, GScanDjb2Modifier)) +#define G_IS_SCAN_DJB2_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_DJB2_MODIFIER)) +#define G_SCAN_DJB2_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_DJB2_MODIFIER, GScanDjb2ModifierClass)) +#define G_IS_SCAN_DJB2_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_DJB2_MODIFIER)) +#define G_SCAN_DJB2_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_DJB2_MODIFIER, GScanDjb2ModifierClass)) + + +/* Transormation en empreinte d'API DJB2 (instance) */ +typedef GApiHashModifier GScanDjb2Modifier; + +/* Transormation en empreinte d'API DJB2 (classe) */ +typedef GApiHashModifierClass GScanDjb2ModifierClass; + + +/* Indique le type défini pour une transormation en empreinte djb2. */ +GType g_scan_djb2_modifier_get_type(void); + +/* Construit un modificateur livrant des empreintes djb2. */ +GScanTokenModifier *g_scan_djb2_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CLASSICS_DJB2_H */ diff --git a/plugins/apihashing/classics/ror13.c b/plugins/apihashing/classics/ror13.c new file mode 100644 index 0000000..e557804 --- /dev/null +++ b/plugins/apihashing/classics/ror13.c @@ -0,0 +1,323 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * ror13.c - transormation en empreinte d'API ror13 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "ror13.h" + + +#include <malloc.h> +#include <string.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en empreintes ror13. */ +static void g_scan_ror13_modifier_class_init(GScanRor13ModifierClass *klass); + +/* Initialise une instance de transmission en empreinte ror13. */ +static void g_scan_ror13_modifier_init(GScanRor13Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_ror13_modifier_dispose(GScanRor13Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_ror13_modifier_finalize(GScanRor13Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_ror13_modifier_get_name(const GScanRor13Modifier *); + +/* Calcule l'empreinte ror13 d'un motif de recherche. */ +static uint32_t compute_ror13(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_ror13_modifier_transform(const GScanRor13Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_ror13_modifier_get_path(const GScanRor13Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte ror13. */ +G_DEFINE_TYPE(GScanRor13Modifier, g_scan_ror13_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en empreintes ror13. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_ror13_modifier_class_init(GScanRor13ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_ror13_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_ror13_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_ror13_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_ror13_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_ror13_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en empreinte ror13. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_ror13_modifier_init(GScanRor13Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_ror13_modifier_dispose(GScanRor13Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_ror13_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_ror13_modifier_finalize(GScanRor13Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_ror13_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des empreintes ror13. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_ror13_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_ROR13_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_ror13_modifier_get_name(const GScanRor13Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("ror13"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte ror13 d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_ror13(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t i; /* Boucle de parcours */ + + result = 0; + + for (i = 0; i < src->len; i++) + result = src->data[i] + ((result << 19) | (result >> 13)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_ror13_modifier_transform(const GScanRor13Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_ror13(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_ror13_modifier_get_path(const GScanRor13Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("ror13"); + + return result; + +} diff --git a/plugins/apihashing/classics/ror13.h b/plugins/apihashing/classics/ror13.h new file mode 100644 index 0000000..43480bd --- /dev/null +++ b/plugins/apihashing/classics/ror13.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * ror13.h - prototypes pour la transormation en empreinte d'API ror13 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CLASSICS_ROR13_H +#define _PLUGINS_APIHASHING_CLASSICS_ROR13_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_ROR13_MODIFIER g_scan_ror13_modifier_get_type() +#define G_SCAN_ROR13_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ROR13_MODIFIER, GScanRor13Modifier)) +#define G_IS_SCAN_ROR13_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ROR13_MODIFIER)) +#define G_SCAN_ROR13_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ROR13_MODIFIER, GScanRor13ModifierClass)) +#define G_IS_SCAN_ROR13_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ROR13_MODIFIER)) +#define G_SCAN_ROR13_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ROR13_MODIFIER, GScanRor13ModifierClass)) + + +/* Transormation en empreinte d'API ror13 (instance) */ +typedef GApiHashModifier GScanRor13Modifier; + +/* Transormation en empreinte d'API ror13 (classe) */ +typedef GApiHashModifierClass GScanRor13ModifierClass; + + +/* Indique le type défini pour une transormation en empreinte ror13. */ +GType g_scan_ror13_modifier_get_type(void); + +/* Construit un modificateur livrant des empreintes ror13. */ +GScanTokenModifier *g_scan_ror13_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CLASSICS_ROR13_H */ diff --git a/plugins/apihashing/core.c b/plugins/apihashing/core.c new file mode 100644 index 0000000..a74a637 --- /dev/null +++ b/plugins/apihashing/core.c @@ -0,0 +1,110 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - prototypes pour le calcul d'encodages + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "core.h" + + +#include <analysis/scan/core.h> +#include <plugins/self.h> + + +#ifdef INCLUDE_PYTHON3_BINDINGS +# include "python/module.h" +# include "python/classics/module.h" +#endif +#include "classics/crc32.h" +#include "classics/djb2.h" +#include "classics/ror13.h" +#include "custom/add1505-shl5.h" +#include "custom/enigma-murmur.h" +#include "custom/imul21-add.h" +#include "custom/imul83-add.h" +#include "custom/sll1-add-hash32.h" +#include "custom/sub-index1.h" +#include "custom/sub42.h" + + +#ifdef INCLUDE_PYTHON3_BINDINGS_ +# define PG_REQ RL("PyChrysalide") +#else +# define PG_REQ NO_REQ +#endif + + + +DEFINE_CHRYSALIDE_PLUGIN("ApiHashing", "API hash computing as ROST modifiers", + PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/formats"), + PG_REQ, AL(PGA_PLUGIN_INIT)); + + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* * +* Description : Prend acte du chargement du greffon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) +{ + bool result; /* Bilan à retourner */ + + result = true; + +#define REGISTER_SCAN_MODIFIER(m) \ + ({ \ + GScanTokenModifier *__mod; \ + bool __status; \ + __mod = m; \ + __status = register_scan_token_modifier(__mod); \ + g_object_unref(G_OBJECT(__mod)); \ + __status; \ + }) + + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_crc32_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_djb2_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_ror13_modifier_new()); + + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_add1505_shl5_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_enigma_murmur_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_imul21_add_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_imul83_add_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_sll1_add_hash32_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_sub42_modifier_new()); + if (result) result = REGISTER_SCAN_MODIFIER(g_scan_sub_index1_modifier_new()); + +#ifdef INCLUDE_PYTHON3_BINDINGS + + if (result) result = add_apihashing_module_to_python_module(); + if (result) result = register_apihashing_classics_modifiers(); + +#endif + + return result; + +} diff --git a/plugins/apihashing/core.h b/plugins/apihashing/core.h new file mode 100644 index 0000000..75a6e73 --- /dev/null +++ b/plugins/apihashing/core.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour le calcul d'encodages + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_ENCODINGS_CORE_H +#define _PLUGINS_ENCODINGS_CORE_H + + +#include <plugins/plugin.h> +#include <plugins/plugin-int.h> + + + +/* Prend acte du chargement du greffon. */ +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *); + + + +#endif /* _PLUGINS_ENCODINGS_CORE_H */ diff --git a/plugins/apihashing/custom/Makefile.am b/plugins/apihashing/custom/Makefile.am new file mode 100644 index 0000000..026addc --- /dev/null +++ b/plugins/apihashing/custom/Makefile.am @@ -0,0 +1,18 @@ + +noinst_LTLIBRARIES = libapihashingcustom.la + +libapihashingcustom_la_SOURCES = \ + add1505-shl5.h add1505-shl5.c \ + enigma-murmur.h enigma-murmur.c \ + imul21-add.h imul21-add.c \ + imul83-add.h imul83-add.c \ + sll1-add-hash32.h sll1-add-hash32.c \ + sub-index1.h sub-index1.c \ + sub42.h sub42.c + +libapihashingcustom_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libapihashingcustom_la_SOURCES:%c=) diff --git a/plugins/apihashing/custom/add1505-shl5.c b/plugins/apihashing/custom/add1505-shl5.c new file mode 100644 index 0000000..db96cf1 --- /dev/null +++ b/plugins/apihashing/custom/add1505-shl5.c @@ -0,0 +1,325 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * add1505-shl5.c - transormation en empreinte d'API add1505-shl5 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "add1505-shl5.h" + + +#include <malloc.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en empreintes add1505-shl5. */ +static void g_scan_add1505_shl5_modifier_class_init(GScanAdd1505Shl5ModifierClass *); + +/* Initialise une instance de transmission en empreinte add1505-shl5. */ +static void g_scan_add1505_shl5_modifier_init(GScanAdd1505Shl5Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_add1505_shl5_modifier_dispose(GScanAdd1505Shl5Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_add1505_shl5_modifier_finalize(GScanAdd1505Shl5Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_add1505_shl5_modifier_get_name(const GScanAdd1505Shl5Modifier *); + +/* Calcule l'empreinte add1505-shl5 d'un motif de recherche. */ +static uint32_t compute_add1505_shl5_hash32(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_add1505_shl5_modifier_transform(const GScanAdd1505Shl5Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_add1505_shl5_modifier_get_path(const GScanAdd1505Shl5Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte add1505-shl5. */ +G_DEFINE_TYPE(GScanAdd1505Shl5Modifier, g_scan_add1505_shl5_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en empreintes add1505-shl5. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_add1505_shl5_modifier_class_init(GScanAdd1505Shl5ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_add1505_shl5_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_add1505_shl5_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_add1505_shl5_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_add1505_shl5_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_add1505_shl5_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en empreinte add1505-shl5. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_add1505_shl5_modifier_init(GScanAdd1505Shl5Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_add1505_shl5_modifier_dispose(GScanAdd1505Shl5Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_add1505_shl5_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_add1505_shl5_modifier_finalize(GScanAdd1505Shl5Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_add1505_shl5_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des empreintes add1505-shl5. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_add1505_shl5_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_add1505_shl5_modifier_get_name(const GScanAdd1505Shl5Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("add1505-shl5"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte add1505-shl5 d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_add1505_shl5_hash32(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t i; /* Boucle de parcours */ + + result = 0x1505; + + for (i = 0; i < src->len; i++) + { + result += (result << 5); + result += src->data[i]; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_add1505_shl5_modifier_transform(const GScanAdd1505Shl5Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_add1505_shl5_hash32(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_add1505_shl5_modifier_get_path(const GScanAdd1505Shl5Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("add1505-shl5"); + + return result; + +} diff --git a/plugins/apihashing/custom/add1505-shl5.h b/plugins/apihashing/custom/add1505-shl5.h new file mode 100644 index 0000000..5e71987 --- /dev/null +++ b/plugins/apihashing/custom/add1505-shl5.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * add1505-shl5.h - prototypes pour la transormation en empreinte d'API add1505-shl5 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CUSTOM_ADD1505_SHL5_H +#define _PLUGINS_APIHASHING_CUSTOM_ADD1505_SHL5_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_ADD1505_SHL5_MODIFIER g_scan_add1505_shl5_modifier_get_type() +#define G_SCAN_ADD1505_SHL5_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, GScanAdd1505Shl5Modifier)) +#define G_IS_SCAN_ADD1505_SHL5_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER)) +#define G_SCAN_ADD1505_SHL5_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, GScanAdd1505Shl5ModifierClass)) +#define G_IS_SCAN_ADD1505_SHL5_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER)) +#define G_SCAN_ADD1505_SHL5_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, GScanAdd1505Shl5ModifierClass)) + + +/* Transormation en empreinte d'API add1505-shl5 (instance) */ +typedef GApiHashModifier GScanAdd1505Shl5Modifier; + +/* Transormation en empreinte d'API add1505-shl5 (classe) */ +typedef GApiHashModifierClass GScanAdd1505Shl5ModifierClass; + + +/* Indique le type défini pour une transormation en empreinte add1505-shl5. */ +GType g_scan_add1505_shl5_modifier_get_type(void); + +/* Construit un modificateur livrant des empreintes add1505-shl5. */ +GScanTokenModifier *g_scan_add1505_shl5_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CUSTOM_ADD1505_SHL5_H */ diff --git a/plugins/apihashing/custom/enigma-murmur.c b/plugins/apihashing/custom/enigma-murmur.c new file mode 100644 index 0000000..cdc35b0 --- /dev/null +++ b/plugins/apihashing/custom/enigma-murmur.c @@ -0,0 +1,377 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enigma-murmur.c - transormation en empreinte d'API enigma-murmur + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "enigma-murmur.h" + + +#include <malloc.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des empreintes enigma-murmur. */ +static void g_scan_enigma_murmur_modifier_class_init(GScanEnigmaMurmurModifierClass *); + +/* Initialise une instance d'empreinte enigma-murmur. */ +static void g_scan_enigma_murmur_modifier_init(GScanEnigmaMurmurModifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_enigma_murmur_modifier_dispose(GScanEnigmaMurmurModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_enigma_murmur_modifier_finalize(GScanEnigmaMurmurModifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_enigma_murmur_modifier_get_name(const GScanEnigmaMurmurModifier *); + +/* Calcule l'empreinte enigma-murmur d'un motif de recherche. */ +static uint32_t compute_enigma_murmur_hash32(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_enigma_murmur_modifier_transform(const GScanEnigmaMurmurModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_enigma_murmur_modifier_get_path(const GScanEnigmaMurmurModifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte enigma-murmur. */ +G_DEFINE_TYPE(GScanEnigmaMurmurModifier, g_scan_enigma_murmur_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des empreintes enigma-murmur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_enigma_murmur_modifier_class_init(GScanEnigmaMurmurModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_enigma_murmur_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_enigma_murmur_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_enigma_murmur_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_enigma_murmur_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_enigma_murmur_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance d'empreinte enigma-murmur. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_enigma_murmur_modifier_init(GScanEnigmaMurmurModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_enigma_murmur_modifier_dispose(GScanEnigmaMurmurModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_enigma_murmur_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_enigma_murmur_modifier_finalize(GScanEnigmaMurmurModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_enigma_murmur_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur pour des empreintes enigma-murmur. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_enigma_murmur_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_enigma_murmur_modifier_get_name(const GScanEnigmaMurmurModifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("enigma-murmur"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte enigma-murmur d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_enigma_murmur_hash32(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t blk_count; /* Nombre de blocs présents */ + size_t i; /* Boucle de parcours */ + uint32_t k; /* Valeur pour un bloc */ + const bin_t *tail; /* Fragement de bloc final */ + + result = 0x4a03bdfa; + + /* Traitement par blocs de 4 octets */ + + blk_count = src->len / 4; + + for (i = 0; i < blk_count; i++) + { + k = ((uint32_t *)src->data)[i]; + + k *= 0xcc9e2d51; + k = (k << 15) | (k >> 17); + k *= 0x1b873593; + + result ^= k; + result = (result << 13) | (result >> 19); + result = result * 5 + 0xe6546b64; + + } + + /* Traitement du reste */ + + tail = src->static_bin_data + 4 * blk_count; + + k = 0; + + switch (src->len & 3) + { + case 3: + k ^= (tail[2] << 16); + + case 2: + k ^= (tail[1] << 8); + + case 1: + k ^= tail[0]; + k *= 0xcc9e2d51; + k = (k << 15) | (k >> (17)); + k *= 0x1b873593; + result ^= k; + break; + + case 0: + break; + + } + + /* Conclusion */ + + result ^= src->len; + + result ^= (result >> 16); + result *= 0x85ebca6b; + result ^= (result >> 13); + result *= 0xc2b2ae35; + result ^= (result >> 16); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_enigma_murmur_modifier_transform(const GScanEnigmaMurmurModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_enigma_murmur_hash32(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_enigma_murmur_modifier_get_path(const GScanEnigmaMurmurModifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("enigma-murmur"); + + return result; + +} diff --git a/plugins/apihashing/custom/enigma-murmur.h b/plugins/apihashing/custom/enigma-murmur.h new file mode 100644 index 0000000..29ae803 --- /dev/null +++ b/plugins/apihashing/custom/enigma-murmur.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enigma-murmur.h - prototypes pour la transormation en empreinte d'API enigma-murmur + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CUSTOM_ENIGMA_MURMUR_H +#define _PLUGINS_APIHASHING_CUSTOM_ENIGMA_MURMUR_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER g_scan_enigma_murmur_modifier_get_type() +#define G_SCAN_ENIGMA_MURMUR_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, GScanEnigmaMurmurModifier)) +#define G_IS_SCAN_ENIGMA_MURMUR_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER)) +#define G_SCAN_ENIGMA_MURMUR_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, GScanEnigmaMurmurModifierClass)) +#define G_IS_SCAN_ENIGMA_MURMUR_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER)) +#define G_SCAN_ENIGMA_MURMUR_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, GScanEnigmaMurmurModifierClass)) + + +/* Transormation en empreinte d'API enigma-murmur (instance) */ +typedef GApiHashModifier GScanEnigmaMurmurModifier; + +/* Transormation en empreinte d'API enigma-murmur (classe) */ +typedef GApiHashModifierClass GScanEnigmaMurmurModifierClass; + + +/* Indique le type défini pour une transormation en empreinte enigma-murmur. */ +GType g_scan_enigma_murmur_modifier_get_type(void); + +/* Construit un modificateur pour des empreintes enigma-murmur. */ +GScanTokenModifier *g_scan_enigma_murmur_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CUSTOM_ENIGMA_MURMUR_H */ diff --git a/plugins/apihashing/custom/imul21-add.c b/plugins/apihashing/custom/imul21-add.c new file mode 100644 index 0000000..2f71910 --- /dev/null +++ b/plugins/apihashing/custom/imul21-add.c @@ -0,0 +1,326 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul21-add.c - transormation en empreinte d'API imul21-add + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "imul21-add.h" + + +#include <malloc.h> +#include <string.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en imul21-add. */ +static void g_scan_imul21_add_modifier_class_init(GScanImul21AddModifierClass *); + +/* Initialise une instance de transmission en imul21-add. */ +static void g_scan_imul21_add_modifier_init(GScanImul21AddModifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_imul21_add_modifier_dispose(GScanImul21AddModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_imul21_add_modifier_finalize(GScanImul21AddModifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_imul21_add_modifier_get_name(const GScanImul21AddModifier *); + +/* Calcule l'empreinte imul21-add d'un motif de recherche. */ +static uint32_t compute_imul21_add(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_imul21_add_modifier_transform(const GScanImul21AddModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_imul21_add_modifier_get_path(const GScanImul21AddModifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte imul21-add. */ +G_DEFINE_TYPE(GScanImul21AddModifier, g_scan_imul21_add_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en imul21-add. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul21_add_modifier_class_init(GScanImul21AddModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_imul21_add_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_imul21_add_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_imul21_add_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_imul21_add_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_imul21_add_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en imul21-add. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul21_add_modifier_init(GScanImul21AddModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul21_add_modifier_dispose(GScanImul21AddModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_imul21_add_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul21_add_modifier_finalize(GScanImul21AddModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_imul21_add_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur vers empreintes imul21-add. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_imul21_add_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_IMUL21_ADD_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_imul21_add_modifier_get_name(const GScanImul21AddModifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("imul21-add"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte imul21-add d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_imul21_add(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t i; /* Boucle de parcours */ + + result = 0; + + for (i = 0; i < src->len; i++) + { + result *= 0x21; + result += src->data[i]; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_imul21_add_modifier_transform(const GScanImul21AddModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_imul21_add(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_imul21_add_modifier_get_path(const GScanImul21AddModifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("imul21-add"); + + return result; + +} diff --git a/plugins/apihashing/custom/imul21-add.h b/plugins/apihashing/custom/imul21-add.h new file mode 100644 index 0000000..fcaa140 --- /dev/null +++ b/plugins/apihashing/custom/imul21-add.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul21-add.h - prototypes pour la transormation en empreinte d'API imul21-add + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CUSTOM_IMUL21_ADD_H +#define _PLUGINS_APIHASHING_CUSTOM_IMUL21_ADD_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_IMUL21_ADD_MODIFIER g_scan_imul21_add_modifier_get_type() +#define G_SCAN_IMUL21_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_IMUL21_ADD_MODIFIER, GScanImul21AddModifier)) +#define G_IS_SCAN_IMUL21_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_IMUL21_ADD_MODIFIER)) +#define G_SCAN_IMUL21_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_IMUL21_ADD_MODIFIER, GScanImul21AddModifierClass)) +#define G_IS_SCAN_IMUL21_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_IMUL21_ADD_MODIFIER)) +#define G_SCAN_IMUL21_ADD_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_IMUL21_ADD_MODIFIER, GScanImul21AddModifierClass)) + + +/* Transformation en empreinte d'API imul21-add (instance) */ +typedef GApiHashModifier GScanImul21AddModifier; + +/* Transformation en empreinte d'API imul21-add (classe) */ +typedef GApiHashModifierClass GScanImul21AddModifierClass; + + +/* Indique le type défini pour une transormation en empreinte imul21-add. */ +GType g_scan_imul21_add_modifier_get_type(void); + +/* Construit un modificateur vers empreintes imul21-add. */ +GScanTokenModifier *g_scan_imul21_add_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CUSTOM_IMUL21_ADD_H */ diff --git a/plugins/apihashing/custom/imul83-add.c b/plugins/apihashing/custom/imul83-add.c new file mode 100644 index 0000000..29f8cf5 --- /dev/null +++ b/plugins/apihashing/custom/imul83-add.c @@ -0,0 +1,326 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul83-add.c - transormation en empreinte d'API imul83-add + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "imul83-add.h" + + +#include <malloc.h> +#include <string.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en imul83-add. */ +static void g_scan_imul83_add_modifier_class_init(GScanImul83AddModifierClass *); + +/* Initialise une instance de transmission en imul83-add. */ +static void g_scan_imul83_add_modifier_init(GScanImul83AddModifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_imul83_add_modifier_dispose(GScanImul83AddModifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_imul83_add_modifier_finalize(GScanImul83AddModifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_imul83_add_modifier_get_name(const GScanImul83AddModifier *); + +/* Calcule l'empreinte imul83-add d'un motif de recherche. */ +static uint32_t compute_imul83_add(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_imul83_add_modifier_transform(const GScanImul83AddModifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_imul83_add_modifier_get_path(const GScanImul83AddModifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte imul83-add. */ +G_DEFINE_TYPE(GScanImul83AddModifier, g_scan_imul83_add_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en imul83-add. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul83_add_modifier_class_init(GScanImul83AddModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_imul83_add_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_imul83_add_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_imul83_add_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_imul83_add_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_imul83_add_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en imul83-add. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul83_add_modifier_init(GScanImul83AddModifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul83_add_modifier_dispose(GScanImul83AddModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_imul83_add_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_imul83_add_modifier_finalize(GScanImul83AddModifier *modifier) +{ + G_OBJECT_CLASS(g_scan_imul83_add_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur vers empreintes imul83-add. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_imul83_add_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_IMUL83_ADD_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_imul83_add_modifier_get_name(const GScanImul83AddModifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("imul83-add"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte imul83-add d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_imul83_add(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t i; /* Boucle de parcours */ + + result = 0; + + for (i = 0; i < src->len; i++) + { + result *= 0x83; + result += src->data[i]; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_imul83_add_modifier_transform(const GScanImul83AddModifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_imul83_add(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_imul83_add_modifier_get_path(const GScanImul83AddModifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("imul83-add"); + + return result; + +} diff --git a/plugins/apihashing/custom/imul83-add.h b/plugins/apihashing/custom/imul83-add.h new file mode 100644 index 0000000..7e376ee --- /dev/null +++ b/plugins/apihashing/custom/imul83-add.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul83-add.h - prototypes pour la transormation en empreinte d'API imul83-add + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CUSTOM_IMUL83_ADD_H +#define _PLUGINS_APIHASHING_CUSTOM_IMUL83_ADD_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_IMUL83_ADD_MODIFIER g_scan_imul83_add_modifier_get_type() +#define G_SCAN_IMUL83_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_IMUL83_ADD_MODIFIER, GScanImul83AddModifier)) +#define G_IS_SCAN_IMUL83_ADD_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_IMUL83_ADD_MODIFIER)) +#define G_SCAN_IMUL83_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_IMUL83_ADD_MODIFIER, GScanImul83AddModifierClass)) +#define G_IS_SCAN_IMUL83_ADD_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_IMUL83_ADD_MODIFIER)) +#define G_SCAN_IMUL83_ADD_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_IMUL83_ADD_MODIFIER, GScanImul83AddModifierClass)) + + +/* Transformation en empreinte d'API imul83-add (instance) */ +typedef GApiHashModifier GScanImul83AddModifier; + +/* Transformation en empreinte d'API imul83-add (classe) */ +typedef GApiHashModifierClass GScanImul83AddModifierClass; + + +/* Indique le type défini pour une transormation en empreinte imul83-add. */ +GType g_scan_imul83_add_modifier_get_type(void); + +/* Construit un modificateur vers empreintes imul83-add. */ +GScanTokenModifier *g_scan_imul83_add_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CUSTOM_IMUL83_ADD_H */ diff --git a/plugins/apihashing/custom/sll1-add-hash32.c b/plugins/apihashing/custom/sll1-add-hash32.c new file mode 100644 index 0000000..de00f81 --- /dev/null +++ b/plugins/apihashing/custom/sll1-add-hash32.c @@ -0,0 +1,326 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sll1-add-hash32.c - transormation en empreinte d'API sll1-add-hash32 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "sll1-add-hash32.h" + + +#include <malloc.h> +#include <string.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en sll1-add-hash32. */ +static void g_scan_sll1_add_hash32_modifier_class_init(GScanSll1AddHash32ModifierClass *klass); + +/* Initialise une instance de transmission en sll1-add-hash32. */ +static void g_scan_sll1_add_hash32_modifier_init(GScanSll1AddHash32Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_sll1_add_hash32_modifier_dispose(GScanSll1AddHash32Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_sll1_add_hash32_modifier_finalize(GScanSll1AddHash32Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_sll1_add_hash32_modifier_get_name(const GScanSll1AddHash32Modifier *); + +/* Calcule l'empreinte sll1-add-hash32 d'un motif de recherche. */ +static uint32_t compute_sll1_add_hash32(const sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_sll1_add_hash32_modifier_transform(const GScanSll1AddHash32Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_sll1_add_hash32_modifier_get_path(const GScanSll1AddHash32Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte sll1-add-hash32. */ +G_DEFINE_TYPE(GScanSll1AddHash32Modifier, g_scan_sll1_add_hash32_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en sll1-add-hash32. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sll1_add_hash32_modifier_class_init(GScanSll1AddHash32ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sll1_add_hash32_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_sll1_add_hash32_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_sll1_add_hash32_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_sll1_add_hash32_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_sll1_add_hash32_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en sll1-add-hash32. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sll1_add_hash32_modifier_init(GScanSll1AddHash32Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sll1_add_hash32_modifier_dispose(GScanSll1AddHash32Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_sll1_add_hash32_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sll1_add_hash32_modifier_finalize(GScanSll1AddHash32Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_sll1_add_hash32_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur vers empreintes sll1-add-hash32. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_sll1_add_hash32_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_sll1_add_hash32_modifier_get_name(const GScanSll1AddHash32Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("sll1-add-hash32"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : src = séquence d'octets à traiter. * +* * +* Description : Calcule l'empreinte sll1-add-hash32 d'un motif de recherche. * +* * +* Retour : Valeur entière de l'empreinte déterminée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static uint32_t compute_sll1_add_hash32(const sized_binary_t *src) +{ + uint32_t result; /* Valeur à retourner */ + size_t i; /* Boucle de parcours */ + + result = 0; + + for (i = 0; i < src->len; i++) + { + result += (src->data[i] | 0x60); + result <<= 1; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_sll1_add_hash32_modifier_transform(const GScanSll1AddHash32Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + uint32_t hash; /* Valeur d'empreinte calculée */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + hash = compute_sll1_add_hash32(_src); + + binary->data = malloc(sizeof(hash) * sizeof(bin_t)); + binary->len = sizeof(hash); + + memcpy(binary->data, &hash, sizeof(hash)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_sll1_add_hash32_modifier_get_path(const GScanSll1AddHash32Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("sll1-add-hash32"); + + return result; + +} diff --git a/plugins/apihashing/custom/sll1-add-hash32.h b/plugins/apihashing/custom/sll1-add-hash32.h new file mode 100644 index 0000000..39abee2 --- /dev/null +++ b/plugins/apihashing/custom/sll1-add-hash32.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sll1-add-hash32.h - prototypes pour la transormation en empreinte d'API sll1-add-hash32 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CUSTOM_SLL1_ADD_HASH32_H +#define _PLUGINS_APIHASHING_CUSTOM_SLL1_ADD_HASH32_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER g_scan_sll1_add_hash32_modifier_get_type() +#define G_SCAN_SLL1_ADD_HASH32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, GScanSll1AddHash32Modifier)) +#define G_IS_SCAN_SLL1_ADD_HASH32_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER)) +#define G_SCAN_SLL1_ADD_HASH32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, GScanSll1AddHash32ModifierClass)) +#define G_IS_SCAN_SLL1_ADD_HASH32_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER)) +#define G_SCAN_SLL1_ADD_HASH32_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, GScanSll1AddHash32ModifierClass)) + + +/* Transormation en empreinte d'API sll1_add_hash32 (instance) */ +typedef GApiHashModifier GScanSll1AddHash32Modifier; + +/* Transormation en empreinte d'API sll1_add_hash32 (classe) */ +typedef GApiHashModifierClass GScanSll1AddHash32ModifierClass; + + +/* Indique le type défini pour une transormation en empreinte sll1-add-hash32. */ +GType g_scan_sll1_add_hash32_modifier_get_type(void); + +/* Construit un modificateur vers empreintes sll1-add-hash32. */ +GScanTokenModifier *g_scan_sll1_add_hash32_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CUSTOM_SLL1_ADD_HASH32_H */ diff --git a/plugins/apihashing/custom/sub-index1.c b/plugins/apihashing/custom/sub-index1.c new file mode 100644 index 0000000..79eafd8 --- /dev/null +++ b/plugins/apihashing/custom/sub-index1.c @@ -0,0 +1,291 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub-index1.c - transormation en empreinte d'API sub-index1 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "sub-index1.h" + + +#include <malloc.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en sub-index1. */ +static void g_scan_sub_index1_modifier_class_init(GScanSubIndex1ModifierClass *); + +/* Initialise une instance de transmission en sub-index1. */ +static void g_scan_sub_index1_modifier_init(GScanSubIndex1Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_sub_index1_modifier_dispose(GScanSubIndex1Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_sub_index1_modifier_finalize(GScanSubIndex1Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_sub_index1_modifier_get_name(const GScanSubIndex1Modifier *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_sub_index1_modifier_transform(const GScanSubIndex1Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_sub_index1_modifier_get_path(const GScanSubIndex1Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte sub-index1. */ +G_DEFINE_TYPE(GScanSubIndex1Modifier, g_scan_sub_index1_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en sub-index1. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub_index1_modifier_class_init(GScanSubIndex1ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sub_index1_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_sub_index1_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_sub_index1_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_sub_index1_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_sub_index1_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en sub-index1. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub_index1_modifier_init(GScanSubIndex1Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub_index1_modifier_dispose(GScanSubIndex1Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_sub_index1_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub_index1_modifier_finalize(GScanSubIndex1Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_sub_index1_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des empreintes sub-index1. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_sub_index1_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SUB_INDEX1_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_sub_index1_modifier_get_name(const GScanSubIndex1Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("sub-index1"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_sub_index1_modifier_transform(const GScanSubIndex1Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + size_t k; /* Boucle de parcours #2 */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + binary->len = _src->len; + binary->data = malloc(binary->len); + + for (k = 0; k < _src->len; k++) + binary->data[k] = _src->data[k] + k + 1; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_sub_index1_modifier_get_path(const GScanSubIndex1Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("sub-index1"); + + return result; + +} diff --git a/plugins/apihashing/custom/sub-index1.h b/plugins/apihashing/custom/sub-index1.h new file mode 100644 index 0000000..b2acc06 --- /dev/null +++ b/plugins/apihashing/custom/sub-index1.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub-index1.h - prototypes pour la transormation en empreinte d'API sub-index1 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CUSTOM_SUB_INDEX1_H +#define _PLUGINS_APIHASHING_CUSTOM_SUB_INDEX1_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_SUB_INDEX1_MODIFIER g_scan_sub_index1_modifier_get_type() +#define G_SCAN_SUB_INDEX1_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SUB_INDEX1_MODIFIER, GScanSubIndex1Modifier)) +#define G_IS_SCAN_SUB_INDEX1_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SUB_INDEX1_MODIFIER)) +#define G_SCAN_SUB_INDEX1_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SUB_INDEX1_MODIFIER, GScanSubIndex1ModifierClass)) +#define G_IS_SCAN_SUB_INDEX1_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SUB_INDEX1_MODIFIER)) +#define G_SCAN_SUB_INDEX1_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SUB_INDEX1_MODIFIER, GScanSubIndex1ModifierClass)) + + +/* Transormation en empreinte d'API sub-index1 (instance) */ +typedef GApiHashModifier GScanSubIndex1Modifier; + +/* Transormation en empreinte d'API sub-index1 (classe) */ +typedef GApiHashModifierClass GScanSubIndex1ModifierClass; + + +/* Indique le type défini pour une transormation en empreinte sub-index1. */ +GType g_scan_sub_index1_modifier_get_type(void); + +/* Construit un modificateur livrant des empreintes sub-index1. */ +GScanTokenModifier *g_scan_sub_index1_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CUSTOM_SUB_INDEX1_H */ diff --git a/plugins/apihashing/custom/sub42.c b/plugins/apihashing/custom/sub42.c new file mode 100644 index 0000000..95bd49d --- /dev/null +++ b/plugins/apihashing/custom/sub42.c @@ -0,0 +1,291 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub42.c - transormation en empreinte d'API sub42 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "sub42.h" + + +#include <malloc.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en empreintes sub42. */ +static void g_scan_sub42_modifier_class_init(GScanSub42ModifierClass *); + +/* Initialise une instance de transmission en empreinte sub42. */ +static void g_scan_sub42_modifier_init(GScanSub42Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_sub42_modifier_dispose(GScanSub42Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_sub42_modifier_finalize(GScanSub42Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_sub42_modifier_get_name(const GScanSub42Modifier *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_sub42_modifier_transform(const GScanSub42Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_sub42_modifier_get_path(const GScanSub42Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en empreinte sub42. */ +G_DEFINE_TYPE(GScanSub42Modifier, g_scan_sub42_modifier, G_TYPE_API_HASH_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en empreintes sub42. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub42_modifier_class_init(GScanSub42ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_sub42_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_sub42_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_sub42_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_sub42_modifier_transform; + modifier->get_path = (get_modifier_path)g_scan_sub42_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en empreinte sub42. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub42_modifier_init(GScanSub42Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub42_modifier_dispose(GScanSub42Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_sub42_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_sub42_modifier_finalize(GScanSub42Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_sub42_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des empreintes sub42. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_sub42_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_SUB42_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_sub42_modifier_get_name(const GScanSub42Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("sub42"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_sub42_modifier_transform(const GScanSub42Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + size_t k; /* Boucle de parcours #2 */ + + result = true; + + *dcount = scount; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount; i++, binary++) + { + _src = src + i; + + binary->len = _src->len; + binary->data = malloc(binary->len); + + for (k = 0; k < _src->len; k++) + binary->data[k] = _src->data[k] + 0x42; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_sub42_modifier_get_path(const GScanSub42Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 0) + { + result = NULL; + (*index)--; + } + + else + result = strdup("sub42"); + + return result; + +} diff --git a/plugins/apihashing/custom/sub42.h b/plugins/apihashing/custom/sub42.h new file mode 100644 index 0000000..8a11741 --- /dev/null +++ b/plugins/apihashing/custom/sub42.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub42.h - prototypes pour la transormation en empreinte d'API sub42 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_APIHASHING_CUSTOM_SUB42_H +#define _PLUGINS_APIHASHING_CUSTOM_SUB42_H + + +#include <glib-object.h> + + +#include "../apihash.h" + + + +#define G_TYPE_SCAN_SUB42_MODIFIER g_scan_sub42_modifier_get_type() +#define G_SCAN_SUB42_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_SUB42_MODIFIER, GScanSub42Modifier)) +#define G_IS_SCAN_SUB42_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_SUB42_MODIFIER)) +#define G_SCAN_SUB42_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_SUB42_MODIFIER, GScanSub42ModifierClass)) +#define G_IS_SCAN_SUB42_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_SUB42_MODIFIER)) +#define G_SCAN_SUB42_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_SUB42_MODIFIER, GScanSub42ModifierClass)) + + +/* Transormation en empreinte d'API sub42 (instance) */ +typedef GApiHashModifier GScanSub42Modifier; + +/* Transormation en empreinte d'API sub42 (classe) */ +typedef GApiHashModifierClass GScanSub42ModifierClass; + + +/* Indique le type défini pour une transormation en empreinte sub42. */ +GType g_scan_sub42_modifier_get_type(void); + +/* Construit un modificateur livrant des empreintes sub42. */ +GScanTokenModifier *g_scan_sub42_modifier_new(void); + + + +#endif /* _PLUGINS_APIHASHING_CUSTOM_SUB42_H */ diff --git a/plugins/apihashing/python/Makefile.am b/plugins/apihashing/python/Makefile.am new file mode 100644 index 0000000..d94218d --- /dev/null +++ b/plugins/apihashing/python/Makefile.am @@ -0,0 +1,20 @@ + +noinst_LTLIBRARIES = libapihashingpython.la + +libapihashingpython_la_SOURCES = \ + apihash.h apihash.c \ + module.h module.c + +libapihashingpython_la_LIBADD = \ + classics/libapihashingpythonclassics.la + +libapihashingpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libapihashingpython_la_SOURCES:%c=) + + +SUBDIRS = classics diff --git a/plugins/apihashing/python/apihash.c b/plugins/apihashing/python/apihash.c new file mode 100644 index 0000000..a3ae519 --- /dev/null +++ b/plugins/apihashing/python/apihash.c @@ -0,0 +1,212 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.c - équivalent Python du fichier "plugins/encodings/rost/base64.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "apihash.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/scan/patterns/modifier.h> + + +#include "../apihash.h" + + + +CREATE_DYN_CONSTRUCTOR(api_hash_modifier, G_TYPE_API_HASH_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_api_hash_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_api_hash_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define API_HASH_MODIFIER_DOC \ + "The *ApiHashModifier* class is the base object for all algorithms" \ + " involed in malwares and revolving API functions to call from" \ + " a hash value.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ApiHashModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_api_hash_modifier_type(void) +{ + static PyMethodDef py_api_hash_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_api_hash_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_api_hash_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.apihashing.ApiHashModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = API_HASH_MODIFIER_DOC, + + .tp_methods = py_api_hash_modifier_methods, + .tp_getset = py_api_hash_modifier_getseters, + + .tp_init = py_api_hash_modifier_init, + .tp_new = py_api_hash_modifier_new, + + }; + + return &py_api_hash_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.....ApiHashModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_api_hash_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python Base64Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_api_hash_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.apihashing"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_API_HASH_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation par empreinte d'API. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_api_hash_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_api_hash_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to API hash modifier"); + break; + + case 1: + *((GApiHashModifier **)dst) = G_API_HASH_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/apihash.h b/plugins/apihashing/python/apihash.h new file mode 100644 index 0000000..5474d49 --- /dev/null +++ b/plugins/apihashing/python/apihash.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.h - équivalent Python du fichier "plugins/encodings/rost/base64.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H +#define _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_api_hash_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.apihashing.ApiHashModifier'. */ +bool ensure_python_api_hash_modifier_is_registered(void); + +/* Tente de convertir en transformation par empreinte d'API. */ +int convert_to_api_hash_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H */ diff --git a/plugins/apihashing/python/classics/Makefile.am b/plugins/apihashing/python/classics/Makefile.am new file mode 100644 index 0000000..316e13f --- /dev/null +++ b/plugins/apihashing/python/classics/Makefile.am @@ -0,0 +1,16 @@ + +noinst_LTLIBRARIES = libapihashingpythonclassics.la + +libapihashingpythonclassics_la_SOURCES = \ + crc32.h crc32.c \ + djb2.h djb2.c \ + module.h module.c \ + ror13.h ror13.c + +libapihashingpythonclassics_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libapihashingpythonclassics_la_SOURCES:%c=) diff --git a/plugins/apihashing/python/classics/crc32.c b/plugins/apihashing/python/classics/crc32.c new file mode 100644 index 0000000..d7c6f7c --- /dev/null +++ b/plugins/apihashing/python/classics/crc32.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * crc32.c - équivalent Python du fichier "plugins/apihashing/classics/crc32.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "crc32.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../classics/crc32.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_crc32_modifier, G_TYPE_SCAN_CRC32_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_crc32_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_crc32_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_CRC32_MODIFIER_DOC \ + "The *Crc32Modifier* class transforms a byte pattern into its" \ + " crc32 encoded form.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Crc32Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_crc32_modifier_type(void) +{ + static PyMethodDef py_scan_crc32_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_crc32_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_crc32_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Crc32Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_CRC32_MODIFIER_DOC, + + .tp_methods = py_scan_crc32_modifier_methods, + .tp_getset = py_scan_crc32_modifier_getseters, + + .tp_init = py_scan_crc32_modifier_init, + .tp_new = py_scan_crc32_modifier_new, + + }; + + return &py_scan_crc32_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....Crc32Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_crc32_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python Crc32Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_crc32_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_CRC32_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation en empreinte crc32. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_crc32_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_crc32_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to crc32 modifier"); + break; + + case 1: + *((GScanCrc32Modifier **)dst) = G_SCAN_CRC32_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/classics/crc32.h b/plugins/apihashing/python/classics/crc32.h new file mode 100644 index 0000000..118a916 --- /dev/null +++ b/plugins/apihashing/python/classics/crc32.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * crc32.h - équivalent Python du fichier "plugins/apihashing/classics/crc32.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_CRC32_H +#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_CRC32_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_crc32_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Crc32Modifier'. */ +bool ensure_python_scan_crc32_modifier_is_registered(void); + +/* Tente de convertir en transformation en empreinte crc32. */ +int convert_to_scan_crc32_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_CRC32_H */ diff --git a/plugins/apihashing/python/classics/djb2.c b/plugins/apihashing/python/classics/djb2.c new file mode 100644 index 0000000..f3d0844 --- /dev/null +++ b/plugins/apihashing/python/classics/djb2.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * djb2.c - équivalent Python du fichier "plugins/apihashing/classics/djb2.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "djb2.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../classics/djb2.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_djb2_modifier, G_TYPE_SCAN_DJB2_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_djb2_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_djb2_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_DJB2_MODIFIER_DOC \ + "The *Djb2Modifier* class transforms a byte pattern into its" \ + " djb2 encoded form.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Djb2Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_djb2_modifier_type(void) +{ + static PyMethodDef py_scan_djb2_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_djb2_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_djb2_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Djb2Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_DJB2_MODIFIER_DOC, + + .tp_methods = py_scan_djb2_modifier_methods, + .tp_getset = py_scan_djb2_modifier_getseters, + + .tp_init = py_scan_djb2_modifier_init, + .tp_new = py_scan_djb2_modifier_new, + + }; + + return &py_scan_djb2_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....Djb2Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_djb2_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python Djb2Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_djb2_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_DJB2_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation en empreinte djb2. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_djb2_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_djb2_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to djb2 modifier"); + break; + + case 1: + *((GScanDjb2Modifier **)dst) = G_SCAN_DJB2_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/classics/djb2.h b/plugins/apihashing/python/classics/djb2.h new file mode 100644 index 0000000..b4086f8 --- /dev/null +++ b/plugins/apihashing/python/classics/djb2.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * djb2.h - équivalent Python du fichier "plugins/apihashing/classics/djb2.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_DJB2_H +#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_DJB2_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_djb2_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Djb2Modifier'. */ +bool ensure_python_scan_djb2_modifier_is_registered(void); + +/* Tente de convertir en transformation en empreinte djb2. */ +int convert_to_scan_djb2_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_DJB2_H */ diff --git a/plugins/apihashing/python/classics/module.c b/plugins/apihashing/python/classics/module.c new file mode 100644 index 0000000..b00757a --- /dev/null +++ b/plugins/apihashing/python/classics/module.c @@ -0,0 +1,68 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire classics en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "crc32.h" +#include "djb2.h" +#include "ror13.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les modificateurs d'empreintes classiques pour ROST. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_apihashing_classics_modifiers(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_crc32_modifier_is_registered(); + if (result) result = ensure_python_scan_djb2_modifier_is_registered(); + if (result) result = ensure_python_scan_ror13_modifier_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/apihashing/python/classics/module.h b/plugins/apihashing/python/classics/module.h new file mode 100644 index 0000000..10c817d --- /dev/null +++ b/plugins/apihashing/python/classics/module.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire classics en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_MODULE_H +#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_MODULE_H + + +#include <stdbool.h> + + + +/* Intègre les modificateurs d'empreintes classiques pour ROST. */ +bool register_apihashing_classics_modifiers(void); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_MODULE_H */ diff --git a/plugins/apihashing/python/classics/ror13.c b/plugins/apihashing/python/classics/ror13.c new file mode 100644 index 0000000..429f7da --- /dev/null +++ b/plugins/apihashing/python/classics/ror13.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * ror13.c - équivalent Python du fichier "plugins/apihashing/classics/ror13.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "ror13.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../classics/ror13.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_ror13_modifier, G_TYPE_SCAN_ROR13_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_ror13_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_ror13_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_ROR13_MODIFIER_DOC \ + "The *Ror13Modifier* class transforms a byte pattern into its" \ + " ror13 encoded form.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Ror13Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_ror13_modifier_type(void) +{ + static PyMethodDef py_scan_ror13_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_ror13_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_ror13_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Ror13Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_ROR13_MODIFIER_DOC, + + .tp_methods = py_scan_ror13_modifier_methods, + .tp_getset = py_scan_ror13_modifier_getseters, + + .tp_init = py_scan_ror13_modifier_init, + .tp_new = py_scan_ror13_modifier_new, + + }; + + return &py_scan_ror13_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....Ror13Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_ror13_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python Ror13Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_ror13_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_ROR13_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation en empreinte ror13. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_ror13_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_ror13_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ror13 modifier"); + break; + + case 1: + *((GScanRor13Modifier **)dst) = G_SCAN_ROR13_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/classics/ror13.h b/plugins/apihashing/python/classics/ror13.h new file mode 100644 index 0000000..021a516 --- /dev/null +++ b/plugins/apihashing/python/classics/ror13.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * ror13.h - équivalent Python du fichier "plugins/apihashing/classics/ror13.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CLASSICS_ROR13_H +#define _PLUGINS_APIHASHING_PYTHON_CLASSICS_ROR13_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_ror13_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Ror13Modifier'. */ +bool ensure_python_scan_ror13_modifier_is_registered(void); + +/* Tente de convertir en transformation en empreinte ror13. */ +int convert_to_scan_ror13_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CLASSICS_ROR13_H */ diff --git a/plugins/apihashing/python/custom/Makefile.am b/plugins/apihashing/python/custom/Makefile.am new file mode 100644 index 0000000..5fbb11f --- /dev/null +++ b/plugins/apihashing/python/custom/Makefile.am @@ -0,0 +1,20 @@ + +noinst_LTLIBRARIES = libapihashingpythoncustom.la + +libapihashingpythoncustom_la_SOURCES = \ + add1505-shl5.h add1505-shl5.c \ + enigma-murmur.h enigma-murmur.c \ + imul21-add.h imul21-add.c \ + imul83-add.h imul83-add.c \ + module.h module.c \ + sll1-add-hash32.h sll1-add-hash32.c \ + sub-index1.h sub-index1.c \ + sub42.h sub42.c + +libapihashingpythoncustom_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libapihashingpythoncustom_la_SOURCES:%c=) diff --git a/plugins/apihashing/python/custom/add1505-shl5.c b/plugins/apihashing/python/custom/add1505-shl5.c new file mode 100644 index 0000000..f70323c --- /dev/null +++ b/plugins/apihashing/python/custom/add1505-shl5.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * add1505-shl5.c - équivalent Python du fichier "plugins/apihashing/custom/add1505-shl5.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "add1505-shl5.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../custom/add1505-shl5.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_add1505_shl5_modifier, G_TYPE_SCAN_ADD1505_SHL5_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_add1505_shl5_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_add1505_shl5_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_ADD1505_SHL5_MODIFIER_DOC \ + "The *Add1505Shl5Modifier* class transforms a byte pattern" \ + " using a add1505-shl5 hash.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Add1505Shl5Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_add1505_shl5_modifier_type(void) +{ + static PyMethodDef py_scan_add1505_shl5_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_add1505_shl5_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_add1505_shl5_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Add1505Shl5Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_ADD1505_SHL5_MODIFIER_DOC, + + .tp_methods = py_scan_add1505_shl5_modifier_methods, + .tp_getset = py_scan_add1505_shl5_modifier_getseters, + + .tp_init = py_scan_add1505_shl5_modifier_init, + .tp_new = py_scan_add1505_shl5_modifier_new, + + }; + + return &py_scan_add1505_shl5_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet '...Add1505Shl5Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_add1505_shl5_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Add1505Shl5Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_add1505_shl5_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_ADD1505_SHL5_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en empreinte add1505-shl5. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_add1505_shl5_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_add1505_shl5_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to add1505-shl5 modifier"); + break; + + case 1: + *((GScanAdd1505Shl5Modifier **)dst) = G_SCAN_ADD1505_SHL5_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/custom/add1505-shl5.h b/plugins/apihashing/python/custom/add1505-shl5.h new file mode 100644 index 0000000..941d6ce --- /dev/null +++ b/plugins/apihashing/python/custom/add1505-shl5.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * add1505-shl5.h - équivalent Python du fichier "plugins/apihashing/custom/add1505-shl5.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_ADD1505_SHL5_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_ADD1505_SHL5_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_add1505_shl5_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Add1505Shl5Modifier'. */ +bool ensure_python_scan_add1505_shl5_modifier_is_registered(void); + +/* Tente de convertir en empreinte add1505-shl5. */ +int convert_to_scan_add1505_shl5_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_ADD1505_SHL5_H */ diff --git a/plugins/apihashing/python/custom/enigma-murmur.c b/plugins/apihashing/python/custom/enigma-murmur.c new file mode 100644 index 0000000..f544f1a --- /dev/null +++ b/plugins/apihashing/python/custom/enigma-murmur.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enigma-murmur.c - équivalent Python du fichier "plugins/apihashing/custom/enigma-murmur.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "enigma-murmur.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../custom/enigma-murmur.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_enigma_murmur_modifier, G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_enigma_murmur_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_enigma_murmur_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_ENIGMA_MURMUR_MODIFIER_DOC \ + "The *EnigmaMurmurModifier* class transforms a byte pattern" \ + " using a enigma-murmur hash.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " EnigmaMurmurModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_enigma_murmur_modifier_type(void) +{ + static PyMethodDef py_scan_enigma_murmur_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_enigma_murmur_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_enigma_murmur_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.EnigmaMurmurModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_ENIGMA_MURMUR_MODIFIER_DOC, + + .tp_methods = py_scan_enigma_murmur_modifier_methods, + .tp_getset = py_scan_enigma_murmur_modifier_getseters, + + .tp_init = py_scan_enigma_murmur_modifier_init, + .tp_new = py_scan_enigma_murmur_modifier_new, + + }; + + return &py_scan_enigma_murmur_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet '...EnigmaMurmurModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_enigma_murmur_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type EnigmaMurmurModifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_enigma_murmur_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_ENIGMA_MURMUR_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en empreinte enigma-murmur. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_enigma_murmur_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_enigma_murmur_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to enigma-murmur modifier"); + break; + + case 1: + *((GScanEnigmaMurmurModifier **)dst) = G_SCAN_ENIGMA_MURMUR_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/custom/enigma-murmur.h b/plugins/apihashing/python/custom/enigma-murmur.h new file mode 100644 index 0000000..8435dae --- /dev/null +++ b/plugins/apihashing/python/custom/enigma-murmur.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enigma-murmur.h - équivalent Python du fichier "plugins/apihashing/custom/enigma-murmur.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_ENIGMA_MURMUR_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_ENIGMA_MURMUR_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_enigma_murmur_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.EnigmaMurmurModifier'. */ +bool ensure_python_scan_enigma_murmur_modifier_is_registered(void); + +/* Tente de convertir en empreinte enigma-murmur. */ +int convert_to_scan_enigma_murmur_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_ENIGMA_MURMUR_H */ diff --git a/plugins/apihashing/python/custom/imul21-add.c b/plugins/apihashing/python/custom/imul21-add.c new file mode 100644 index 0000000..aadc6cc --- /dev/null +++ b/plugins/apihashing/python/custom/imul21-add.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul21-add.c - équivalent Python du fichier "plugins/apihashing/custom/imul21-add.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "imul21-add.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../custom/imul21-add.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_imul21_add_modifier, G_TYPE_SCAN_IMUL21_ADD_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_imul21_add_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_imul21_add_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_IMUL21_ADD_MODIFIER_DOC \ + "The *Sll1AddHash32Modifier* class transforms a byte pattern" \ + " using a variation of the sll1 algorithm.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Sll1AddHash32Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_imul21_add_modifier_type(void) +{ + static PyMethodDef py_scan_imul21_add_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_imul21_add_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_imul21_add_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Imul21AddModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_IMUL21_ADD_MODIFIER_DOC, + + .tp_methods = py_scan_imul21_add_modifier_methods, + .tp_getset = py_scan_imul21_add_modifier_getseters, + + .tp_init = py_scan_imul21_add_modifier_init, + .tp_new = py_scan_imul21_add_modifier_new, + + }; + + return &py_scan_imul21_add_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet '...Imul21AddModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_imul21_add_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Sll1AddHash32Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_imul21_add_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_IMUL21_ADD_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en empreinte imul21-add. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_imul21_add_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_imul21_add_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to imul21-add modifier"); + break; + + case 1: + *((GScanImul21AddModifier **)dst) = G_SCAN_IMUL21_ADD_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/custom/imul21-add.h b/plugins/apihashing/python/custom/imul21-add.h new file mode 100644 index 0000000..3fcc053 --- /dev/null +++ b/plugins/apihashing/python/custom/imul21-add.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul21-add.h - équivalent Python du fichier "plugins/apihashing/custom/imul21-add.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL21_ADD_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL21_ADD_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_imul21_add_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Imul21AddModifier'. */ +bool ensure_python_scan_imul21_add_modifier_is_registered(void); + +/* Tente de convertir en empreinte imul21-add. */ +int convert_to_scan_imul21_add_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL21_ADD_H */ diff --git a/plugins/apihashing/python/custom/imul83-add.c b/plugins/apihashing/python/custom/imul83-add.c new file mode 100644 index 0000000..5e2d929 --- /dev/null +++ b/plugins/apihashing/python/custom/imul83-add.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul83-add.c - équivalent Python du fichier "plugins/apihashing/custom/imul83-add.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "imul83-add.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../custom/imul83-add.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_imul83_add_modifier, G_TYPE_SCAN_IMUL83_ADD_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_imul83_add_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_imul83_add_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_IMUL83_ADD_MODIFIER_DOC \ + "The *Sll1AddHash32Modifier* class transforms a byte pattern" \ + " using a variation of the sll1 algorithm.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Sll1AddHash32Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_imul83_add_modifier_type(void) +{ + static PyMethodDef py_scan_imul83_add_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_imul83_add_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_imul83_add_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Imul83AddModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_IMUL83_ADD_MODIFIER_DOC, + + .tp_methods = py_scan_imul83_add_modifier_methods, + .tp_getset = py_scan_imul83_add_modifier_getseters, + + .tp_init = py_scan_imul83_add_modifier_init, + .tp_new = py_scan_imul83_add_modifier_new, + + }; + + return &py_scan_imul83_add_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet '...Imul83AddModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_imul83_add_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Sll1AddHash32Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_imul83_add_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_IMUL83_ADD_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en empreinte imul83-add. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_imul83_add_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_imul83_add_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to imul83-add modifier"); + break; + + case 1: + *((GScanImul83AddModifier **)dst) = G_SCAN_IMUL83_ADD_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/custom/imul83-add.h b/plugins/apihashing/python/custom/imul83-add.h new file mode 100644 index 0000000..fd05136 --- /dev/null +++ b/plugins/apihashing/python/custom/imul83-add.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * imul83-add.h - équivalent Python du fichier "plugins/apihashing/custom/imul83-add.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL83_ADD_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL83_ADD_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_imul83_add_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Imul83AddModifier'. */ +bool ensure_python_scan_imul83_add_modifier_is_registered(void); + +/* Tente de convertir en empreinte imul83-add. */ +int convert_to_scan_imul83_add_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_IMUL83_ADD_H */ diff --git a/plugins/apihashing/python/custom/module.c b/plugins/apihashing/python/custom/module.c new file mode 100644 index 0000000..07107dd --- /dev/null +++ b/plugins/apihashing/python/custom/module.c @@ -0,0 +1,76 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire custom en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "add1505-shl5.h" +#include "enigma-murmur.h" +#include "imul21-add.h" +#include "imul83-add.h" +#include "sll1-add-hash32.h" +#include "sub-index1.h" +#include "sub42.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les modificateurs d'empreintes particulières à ROST. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_apihashing_custom_modifiers(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_add1505_shl5_modifier_is_registered(); + if (result) result = ensure_python_scan_enigma_murmur_modifier_is_registered(); + if (result) result = ensure_python_scan_imul21_add_modifier_is_registered(); + if (result) result = ensure_python_scan_imul83_add_modifier_is_registered(); + if (result) result = ensure_python_scan_sll1_add_hash32_modifier_is_registered(); + if (result) result = ensure_python_scan_sub42_modifier_is_registered(); + if (result) result = ensure_python_scan_sub_index1_modifier_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/apihashing/python/custom/module.h b/plugins/apihashing/python/custom/module.h new file mode 100644 index 0000000..9073651 --- /dev/null +++ b/plugins/apihashing/python/custom/module.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire custom en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_MODULE_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_MODULE_H + + +#include <stdbool.h> + + + +/* Intègre les modificateurs d'empreintes particulières à ROST. */ +bool register_apihashing_custom_modifiers(void); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_MODULE_H */ diff --git a/plugins/apihashing/python/custom/sll1-add-hash32.c b/plugins/apihashing/python/custom/sll1-add-hash32.c new file mode 100644 index 0000000..c63fcf3 --- /dev/null +++ b/plugins/apihashing/python/custom/sll1-add-hash32.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sll1-add-hash32.c - équivalent Python du fichier "plugins/apihashing/custom/sll1-add-hash32.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "sll1-add-hash32.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../custom/sll1-add-hash32.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_sll1_add_hash32_modifier, G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_sll1_add_hash32_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_sll1_add_hash32_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_SLL1_ADD_HASH32_MODIFIER_DOC \ + "The *Sll1AddHash32Modifier* class transforms a byte pattern" \ + " using a variation of the sll1 algorithm.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Sll1AddHash32Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_sll1_add_hash32_modifier_type(void) +{ + static PyMethodDef py_scan_sll1_add_hash32_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_sll1_add_hash32_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_sll1_add_hash32_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Sll1AddHash32Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_SLL1_ADD_HASH32_MODIFIER_DOC, + + .tp_methods = py_scan_sll1_add_hash32_modifier_methods, + .tp_getset = py_scan_sll1_add_hash32_modifier_getseters, + + .tp_init = py_scan_sll1_add_hash32_modifier_init, + .tp_new = py_scan_sll1_add_hash32_modifier_new, + + }; + + return &py_scan_sll1_add_hash32_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet '...Sll1AddHash32Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_sll1_add_hash32_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Sll1AddHash32Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_sll1_add_hash32_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_SLL1_ADD_HASH32_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en empreinte sll1-add-hash32. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_sll1_add_hash32_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_sll1_add_hash32_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to sll1-add-hash32 modifier"); + break; + + case 1: + *((GScanSll1AddHash32Modifier **)dst) = G_SCAN_SLL1_ADD_HASH32_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/custom/sll1-add-hash32.h b/plugins/apihashing/python/custom/sll1-add-hash32.h new file mode 100644 index 0000000..bf11c34 --- /dev/null +++ b/plugins/apihashing/python/custom/sll1-add-hash32.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sll1-add-hash32.h - équivalent Python du fichier "plugins/apihashing/custom/sll1-add-hash32.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_SLL1_ADD_HASH32_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_SLL1_ADD_HASH32_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_sll1_add_hash32_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Sll1AddHash32Modifier'. */ +bool ensure_python_scan_sll1_add_hash32_modifier_is_registered(void); + +/* Tente de convertir en empreinte sll1-add-hash32. */ +int convert_to_scan_sll1_add_hash32_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_SLL1_ADD_HASH32_H */ diff --git a/plugins/apihashing/python/custom/sub-index1.c b/plugins/apihashing/python/custom/sub-index1.c new file mode 100644 index 0000000..e5c1487 --- /dev/null +++ b/plugins/apihashing/python/custom/sub-index1.c @@ -0,0 +1,213 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub-index1.c - équivalent Python du fichier "plugins/apihashing/custom/sub-index1.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "sub-index1.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../custom/sub-index1.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_sub_index1_modifier, G_TYPE_SCAN_SUB_INDEX1_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_sub_index1_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_sub_index1_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_SUB_INDEX1_MODIFIER_DOC \ + "The *SubIndex1Modifier* class produces the encrypted version" \ + " of a byte pattern where the index of a byte is added to its" \ + " value.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Sub-Index1Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_sub_index1_modifier_type(void) +{ + static PyMethodDef py_scan_sub_index1_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_sub_index1_modifier_getseters[] = { + + { NULL } + }; + + static PyTypeObject py_scan_sub_index1_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.SubIndex1Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_SUB_INDEX1_MODIFIER_DOC, + + .tp_methods = py_scan_sub_index1_modifier_methods, + .tp_getset = py_scan_sub_index1_modifier_getseters, + + .tp_init = py_scan_sub_index1_modifier_init, + .tp_new = py_scan_sub_index1_modifier_new, + + }; + + return &py_scan_sub_index1_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....SubIndex1Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_sub_index1_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python Sub-Index1Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_sub_index1_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_SUB_INDEX1_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation en empreinte sub-index1.* +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_sub_index1_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_sub_index1_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to sub-index1 modifier"); + break; + + case 1: + *((GScanSubIndex1Modifier **)dst) = G_SCAN_SUB_INDEX1_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/custom/sub-index1.h b/plugins/apihashing/python/custom/sub-index1.h new file mode 100644 index 0000000..65186f3 --- /dev/null +++ b/plugins/apihashing/python/custom/sub-index1.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub-index1.h - équivalent Python du fichier "plugins/apihashing/custom/sub-index1.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB_INDEX1_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB_INDEX1_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_sub_index1_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.SubIndex1Modifier'. */ +bool ensure_python_scan_sub_index1_modifier_is_registered(void); + +/* Tente de convertir en transformation en empreinte sub-index1. */ +int convert_to_scan_sub_index1_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB_INDEX1_H */ diff --git a/plugins/apihashing/python/custom/sub42.c b/plugins/apihashing/python/custom/sub42.c new file mode 100644 index 0000000..238496d --- /dev/null +++ b/plugins/apihashing/python/custom/sub42.c @@ -0,0 +1,212 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub42.c - équivalent Python du fichier "plugins/apihashing/custom/sub42.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "sub42.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../apihash.h" +#include "../../custom/sub42.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_sub42_modifier, G_TYPE_SCAN_SUB42_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_sub42_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_sub42_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_SUB42_MODIFIER_DOC \ + "The *Sub42Modifier* class produces the encrypted version of a" \ + " byte pattern where 0x42 is added to each byte.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Sub42Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_sub42_modifier_type(void) +{ + static PyMethodDef py_scan_sub42_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_sub42_modifier_getseters[] = { + + { NULL } + }; + + static PyTypeObject py_scan_sub42_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Sub42Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_SUB42_MODIFIER_DOC, + + .tp_methods = py_scan_sub42_modifier_methods, + .tp_getset = py_scan_sub42_modifier_getseters, + + .tp_init = py_scan_sub42_modifier_init, + .tp_new = py_scan_sub42_modifier_new, + + }; + + return &py_scan_sub42_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....Sub42Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_sub42_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python Sub42Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_sub42_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_api_hash_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_SUB42_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation en empreinte sub42. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_sub42_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_sub42_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to sub42 modifier"); + break; + + case 1: + *((GScanSub42Modifier **)dst) = G_SCAN_SUB42_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/apihashing/python/custom/sub42.h b/plugins/apihashing/python/custom/sub42.h new file mode 100644 index 0000000..ce3660a --- /dev/null +++ b/plugins/apihashing/python/custom/sub42.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * sub42.h - équivalent Python du fichier "plugins/apihashing/custom/sub42.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB42_H +#define _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB42_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_sub42_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Sub42Modifier'. */ +bool ensure_python_scan_sub42_modifier_is_registered(void); + +/* Tente de convertir en transformation en empreinte sub42. */ +int convert_to_scan_sub42_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_CUSTOM_SUB42_H */ diff --git a/plugins/apihashing/python/module.c b/plugins/apihashing/python/module.c new file mode 100644 index 0000000..588a0d8 --- /dev/null +++ b/plugins/apihashing/python/module.c @@ -0,0 +1,87 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire apihashing en tant que module + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "apihash.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.apihashing' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_apihashing_module_to_python_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_APIHASHING_DOC \ + "apihashing is a module providing a few implementations" \ + " of algorithms used to resolve API functions by hash." + + static PyModuleDef py_chrysalide_apihashing_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.apihashing", + .m_doc = PYCHRYSALIDE_PLUGINS_APIHASHING_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins"); + + module = build_python_module(super, &py_chrysalide_apihashing_module); + + result = (module != NULL); + + if (result) result = ensure_python_api_hash_modifier_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/apihashing/python/module.h b/plugins/apihashing/python/module.h new file mode 100644 index 0000000..fe628b9 --- /dev/null +++ b/plugins/apihashing/python/module.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire apihashing en tant que module + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_APIHASHING_PYTHON_MODULE_H +#define _PLUGINS_APIHASHING_PYTHON_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.apihashing' au module Python. */ +bool add_apihashing_module_to_python_module(void); + + + +#endif /* _PLUGINS_APIHASHING_PYTHON_MODULE_H */ diff --git a/plugins/arm/Makefile.am b/plugins/arm/Makefile.am index a37cbbd..3470256 100644 --- a/plugins/arm/Makefile.am +++ b/plugins/arm/Makefile.am @@ -35,23 +35,25 @@ PYTHON3_SUBDIRS = python endif -libarm_la_SOURCES = \ - cond.h \ - context-int.h \ - context.h context.c \ - core.h core.c \ - instruction-int.h \ - instruction.h instruction.c \ - link.h link.c \ - processor-int.h \ - processor.h processor.c \ - register-int.h \ +libarm_la_SOURCES = \ + cond.h \ + context-int.h \ + context.h context.c \ + core.h core.c \ + instruction-int.h \ + instruction.h instruction.c \ + link.h link.c \ + processor-int.h \ + processor.h processor.c \ + register-int.h \ register.h register.c -libarm_la_LIBADD = \ - $(PYTHON3_LIBADD) \ +libarm_la_LIBADD = \ + $(PYTHON3_LIBADD) \ v7/libarmv7.la +libarm_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libarm_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -63,9 +65,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libarm_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - SUBDIRS = v7 $(PYTHON3_SUBDIRS) diff --git a/plugins/arm/core.c b/plugins/arm/core.c index c270c85..1c1c6bc 100644 --- a/plugins/arm/core.c +++ b/plugins/arm/core.c @@ -24,17 +24,16 @@ #include "core.h" -#include <config.h> #include <plugins/self.h> -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif #include "v7/core.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -66,7 +65,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) result = init_armv7_core(); -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS if (result) result = add_arch_arm_module_to_python_module(); #endif diff --git a/plugins/arm/instruction.c b/plugins/arm/instruction.c index b08b87c..c42250f 100644 --- a/plugins/arm/instruction.c +++ b/plugins/arm/instruction.c @@ -29,6 +29,7 @@ #include <string.h> +#include <analysis/db/misc/rlestr.h> #include <common/extstr.h> #include <core/logs.h> @@ -55,10 +56,21 @@ static void g_arm_instruction_finalize(GArmInstruction *); /* Charge une instruction depuis une mémoire tampon. */ -static bool g_arm_instruction_unserialize(GArmInstruction *, GAsmStorage *, GBinFormat *, packed_buffer *); +static bool g_arm_instruction_unserialize(GArmInstruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *); /* Sauvegarde une instruction dans une mémoire tampon. */ -static bool g_arm_instruction_serialize(GArmInstruction *, GAsmStorage *, packed_buffer *); +static bool g_arm_instruction_serialize(GArmInstruction *, GAsmStorage *, packed_buffer_t *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_arm_instruction_load(GArmInstruction *, GObjectStorage *, packed_buffer_t *); + +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_arm_instruction_store(GArmInstruction *, GObjectStorage *, packed_buffer_t *); @@ -93,6 +105,9 @@ static void g_arm_instruction_class_init(GArmInstructionClass *klass) instr->unserialize = (unserialize_instruction_fc)g_arm_instruction_unserialize; instr->serialize = (serialize_instruction_fc)g_arm_instruction_serialize; + instr->load = (load_instruction_fc)g_arm_instruction_load; + instr->store = (store_instruction_fc)g_arm_instruction_store; + } @@ -287,7 +302,7 @@ ArmCondCode g_arm_instruction_get_cond(const GArmInstruction *instr) * * ******************************************************************************/ -static bool g_arm_instruction_unserialize(GArmInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static bool g_arm_instruction_unserialize(GArmInstruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchInstructionClass *parent; /* Classe parente à consulter */ @@ -340,7 +355,7 @@ static bool g_arm_instruction_unserialize(GArmInstruction *instr, GAsmStorage *s * * ******************************************************************************/ -static bool g_arm_instruction_serialize(GArmInstruction *instr, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_arm_instruction_serialize(GArmInstruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchInstructionClass *parent; /* Classe parente à consulter */ @@ -382,3 +397,109 @@ static bool g_arm_instruction_serialize(GArmInstruction *instr, GAsmStorage *sto return result; } + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : instr = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * +* * +* Description : Charge un contenu depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_arm_instruction_load(GArmInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchInstructionClass *parent; /* Classe parente à consulter */ + rle_string str; /* Chaîne à charger */ + uleb128_t value; /* Valeur ULEB128 à charger */ + + parent = G_ARCH_INSTRUCTION_CLASS(g_arm_instruction_parent_class); + + result = parent->load(G_ARCH_INSTRUCTION(instr), storage, pbuf); + + if (result) + { + setup_empty_rle_string(&str); + + result = unpack_rle_string(&str, pbuf); + + if (result) + { + result = (get_rle_string(&str) != NULL); + + if (result) + result = g_arm_instruction_extend_keyword(instr, get_rle_string(&str)); + + exit_rle_string(&str); + + } + + } + + if (result) + { + result = unpack_uleb128(&value, pbuf); + + if (result) + instr->cond = value; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à remplir. * +* * +* Description : Sauvegarde un contenu dans une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_arm_instruction_store(GArmInstruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchInstructionClass *parent; /* Classe parente à consulter */ + rle_string str; /* Chaîne à conserver */ + + parent = G_ARCH_INSTRUCTION_CLASS(g_arm_instruction_parent_class); + + result = parent->store(G_ARCH_INSTRUCTION(instr), storage, pbuf); + + if (result) + { + init_static_rle_string(&str, instr->suffix); + + result = pack_rle_string(&str, pbuf); + + exit_rle_string(&str); + + } + + if (result) + result = pack_uleb128((uleb128_t []){ instr->cond }, pbuf); + + return result; + +} diff --git a/plugins/arm/python/Makefile.am b/plugins/arm/python/Makefile.am index f09baee..931b2b9 100644 --- a/plugins/arm/python/Makefile.am +++ b/plugins/arm/python/Makefile.am @@ -1,15 +1,16 @@ noinst_LTLIBRARIES = libarmpython.la -libarmpython_la_SOURCES = \ - instruction.h instruction.c \ - module.h module.c \ +libarmpython_la_SOURCES = \ + instruction.h instruction.c \ + module.h module.c \ processor.h processor.c -libarmpython_la_LIBADD = \ +libarmpython_la_LIBADD = \ v7/libarmpythonv7.la -libarmpython_la_LDFLAGS = +libarmpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -17,9 +18,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libarmpython_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = v7 diff --git a/plugins/arm/python/instruction.c b/plugins/arm/python/instruction.c index 81fd132..8a37d92 100644 --- a/plugins/arm/python/instruction.c +++ b/plugins/arm/python/instruction.c @@ -93,17 +93,19 @@ PyTypeObject *get_python_arm_instruction_type(void) bool register_python_arm_instruction(PyObject *module) { - PyTypeObject *py_arm_instruction_type; /* Type Python 'BinContent' */ + PyTypeObject *type; /* Type Python 'ArmInstruction'*/ PyObject *dict; /* Dictionnaire du module */ - py_arm_instruction_type = get_python_arm_instruction_type(); + type = get_python_arm_instruction_type(); - APPLY_ABSTRACT_FLAG(py_arm_instruction_type); + APPLY_ABSTRACT_FLAG(type); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARM_INSTRUCTION, - py_arm_instruction_type, get_python_arch_instruction_type())) + if (!ensure_python_arch_instruction_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ARM_INSTRUCTION, type)) return false; return true; diff --git a/plugins/arm/python/processor.c b/plugins/arm/python/processor.c index 1681f52..6a31611 100644 --- a/plugins/arm/python/processor.c +++ b/plugins/arm/python/processor.c @@ -93,14 +93,17 @@ PyTypeObject *get_python_arm_processor_type(void) bool register_python_arm_processor(PyObject *module) { - PyTypeObject *py_arm_processor_type; /* Type Python 'BinContent' */ + PyTypeObject *type; /* Type Python 'ArmProcessor' */ PyObject *dict; /* Dictionnaire du module */ - py_arm_processor_type = get_python_arm_processor_type(); + type = get_python_arm_processor_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARM_PROCESSOR, py_arm_processor_type, get_python_arch_processor_type())) + if (!ensure_python_arch_processor_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ARM_PROCESSOR, type)) return false; return true; diff --git a/plugins/arm/python/v7/Makefile.am b/plugins/arm/python/v7/Makefile.am index 06dc4af..a350d90 100644 --- a/plugins/arm/python/v7/Makefile.am +++ b/plugins/arm/python/v7/Makefile.am @@ -1,20 +1,15 @@ noinst_LTLIBRARIES = libarmpythonv7.la -libarmpythonv7_la_SOURCES = \ - instruction.h instruction.c \ - module.h module.c \ +libarmpythonv7_la_SOURCES = \ + instruction.h instruction.c \ + module.h module.c \ processor.h processor.c -libarmpythonv7_la_LDFLAGS = +libarmpythonv7_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libarmpythonv7_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/arm/python/v7/instruction.c b/plugins/arm/python/v7/instruction.c index 81b34c3..27171ac 100644 --- a/plugins/arm/python/v7/instruction.c +++ b/plugins/arm/python/v7/instruction.c @@ -83,7 +83,7 @@ PyTypeObject *get_python_armv7_instruction_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide....arm.ArmInstruction'.* +* Description : Prend en charge l'objet 'pychrysalide.....ArmV7Instruction'. * * * * Retour : Bilan de l'opération. * * * @@ -93,15 +93,16 @@ PyTypeObject *get_python_armv7_instruction_type(void) bool register_python_armv7_instruction(PyObject *module) { - PyTypeObject *py_armv7_instruction_type;/* Type Python 'BinContent' */ + PyTypeObject *type; /* Type 'ArmV7Instruction' */ PyObject *dict; /* Dictionnaire du module */ - py_armv7_instruction_type = get_python_armv7_instruction_type(); + type = get_python_armv7_instruction_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_INSTRUCTION, - py_armv7_instruction_type, get_python_arm_instruction_type())) + /* TODO : ensure get_python_arm_instruction_type() */ + + if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_INSTRUCTION, type)) return false; return true; diff --git a/plugins/arm/python/v7/processor.c b/plugins/arm/python/v7/processor.c index 6a1e3f0..5d5ea5c 100644 --- a/plugins/arm/python/v7/processor.c +++ b/plugins/arm/python/v7/processor.c @@ -83,7 +83,7 @@ PyTypeObject *get_python_armv7_processor_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide.arch.arm.ArmProcessor'.* +* Description : Prend en charge l'objet 'pychrysalide.....ArmV7Processor'. * * * * Retour : Bilan de l'opération. * * * @@ -93,14 +93,16 @@ PyTypeObject *get_python_armv7_processor_type(void) bool register_python_armv7_processor(PyObject *module) { - PyTypeObject *py_armv7_processor_type; /* Type Python 'BinContent' */ + PyTypeObject *type; /* Type Python 'ArmV7Processor'*/ PyObject *dict; /* Dictionnaire du module */ - py_armv7_processor_type = get_python_armv7_processor_type(); + type = get_python_armv7_processor_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_PROCESSOR, py_armv7_processor_type, get_python_arm_processor_type())) + /* TODO : ensure get_python_arm_processor_type() */ + + if (!register_class_for_pygobject(dict, G_TYPE_ARMV7_PROCESSOR, type)) return false; return true; diff --git a/plugins/arm/register.c b/plugins/arm/register.c index 837dfd5..6a58d59 100644 --- a/plugins/arm/register.c +++ b/plugins/arm/register.c @@ -46,22 +46,22 @@ static void g_arm_register_dispose(GArmRegister *); /* Procède à la libération totale de la mémoire. */ static void g_arm_register_finalize(GArmRegister *); -/* Produit une empreinte à partir d'un registre. */ -static guint g_arm_register_hash(const GArmRegister *); -/* Compare un registre avec un autre. */ -static int g_arm_register_compare(const GArmRegister *, const GArmRegister *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* --------------------- TRANSPOSITIONS VIA CACHE DES REGISTRES --------------------- */ +/* Produit une empreinte à partir d'un registre. */ +static guint g_arm_register_hash(const GArmRegister *); +/* Compare un registre avec un autre. */ +static int g_arm_register_compare(const GArmRegister *, const GArmRegister *); -/* Charge un registre depuis une mémoire tampon. */ -static GArchRegister *g_arm_register_unserialize(GArmRegister *, GAsmStorage *, packed_buffer *); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_arm_register_load(GArmRegister *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un registre dans une mémoire tampon. */ -static bool g_arm_register_serialize(const GArmRegister *, GAsmStorage *, packed_buffer *); +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_arm_register_store(GArmRegister *, GObjectStorage *, packed_buffer_t *); @@ -88,20 +88,21 @@ G_DEFINE_TYPE(GArmRegister, g_arm_register, G_TYPE_ARCH_REGISTER); static void g_arm_register_class_init(GArmRegisterClass *klass) { - GObjectClass *object_class; /* Autre version de la classe */ - GArchRegisterClass *reg_class; /* Classe de haut niveau */ + GObjectClass *object; /* Autre version de la classe */ + GArchRegisterClass *reg; /* Classe de haut niveau */ - object_class = G_OBJECT_CLASS(klass); + object = G_OBJECT_CLASS(klass); - object_class->dispose = (GObjectFinalizeFunc/* ! */)g_arm_register_dispose; - object_class->finalize = (GObjectFinalizeFunc)g_arm_register_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_arm_register_dispose; + object->finalize = (GObjectFinalizeFunc)g_arm_register_finalize; - reg_class = G_ARCH_REGISTER_CLASS(klass); + reg = G_ARCH_REGISTER_CLASS(klass); - reg_class->hash = (reg_hash_fc)g_arm_register_hash; - reg_class->compare = (reg_compare_fc)g_arm_register_compare; - reg_class->unserialize = (reg_unserialize_fc)g_arm_register_unserialize; - reg_class->serialize = (reg_serialize_fc)g_arm_register_serialize; + reg->hash = (reg_hash_fc)g_arm_register_hash; + reg->compare = (reg_compare_fc)g_arm_register_compare; + + reg->load = (load_register_fc)g_arm_register_load; + reg->store = (store_register_fc)g_arm_register_store; } @@ -181,6 +182,12 @@ uint8_t g_arm_register_get_index(const GArmRegister *reg) } + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : reg = opérande à consulter pour le calcul. * @@ -224,19 +231,13 @@ static int g_arm_register_compare(const GArmRegister *a, const GArmRegister *b) } - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : reg = registre d'architecture à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : reg = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * * * -* Description : Charge un registre depuis une mémoire tampon. * +* Description : Charge un contenu depuis une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -244,24 +245,17 @@ static int g_arm_register_compare(const GArmRegister *a, const GArmRegister *b) * * ******************************************************************************/ -static GArchRegister *g_arm_register_unserialize(GArmRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_arm_register_load(GArmRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) { - GArchRegister *result; /* Instance à retourner */ + bool result; /* Bilan à retourner */ GArchRegisterClass *parent; /* Classe parente à consulter */ - /** - * L'indice de registre est utilisé par les sous-classes pour la regénération - * à partir du cache. - * - * Il est donc lu depuis le tempon avant l'appel à cette fonction, et est - * ainsi déjà pris en compte. - */ - - result = G_ARCH_REGISTER(reg); - parent = G_ARCH_REGISTER_CLASS(g_arm_register_parent_class); - result = parent->unserialize(result, storage, pbuf); + result = parent->load(G_ARCH_REGISTER(reg), storage, pbuf); + + if (result) + result = extract_packed_buffer(pbuf, ®->index, sizeof(uint8_t), true); return result; @@ -270,11 +264,11 @@ static GArchRegister *g_arm_register_unserialize(GArmRegister *reg, GAsmStorage /****************************************************************************** * * -* Paramètres : reg = registre d'architecture à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : reg = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un registre dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -282,20 +276,17 @@ static GArchRegister *g_arm_register_unserialize(GArmRegister *reg, GAsmStorage * * ******************************************************************************/ -static bool g_arm_register_serialize(const GArmRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_arm_register_store(GArmRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchRegisterClass *parent; /* Classe parente à consulter */ - result = extend_packed_buffer(pbuf, ®->index, sizeof(uint8_t), false); - - if (result) - { - parent = G_ARCH_REGISTER_CLASS(g_arm_register_parent_class); + parent = G_ARCH_REGISTER_CLASS(g_arm_register_parent_class); - result = parent->serialize(G_ARCH_REGISTER(reg), storage, pbuf); + result = parent->store(G_ARCH_REGISTER(reg), storage, pbuf); - } + if (result) + result = extend_packed_buffer(pbuf, ®->index, sizeof(uint8_t), false); return result; diff --git a/plugins/arm/v7/Makefile.am b/plugins/arm/v7/Makefile.am index 5d30876..d87373a 100644 --- a/plugins/arm/v7/Makefile.am +++ b/plugins/arm/v7/Makefile.am @@ -1,36 +1,35 @@ noinst_LTLIBRARIES = libarmv7.la -libarmv7_la_SOURCES = \ - arm.h arm.c \ - context.h context.c \ - core.h core.c \ - fetch.h fetch.c \ - helpers.h \ - instruction.h instruction.c \ - link.h link.c \ - post.h post.c \ - processor.h processor.c \ - pseudo.h pseudo.c \ - register-int.h \ - register.h register.c \ - thumb_16.h thumb_16.c \ +libarmv7_la_SOURCES = \ + arm.h arm.c \ + context.h context.c \ + core.h core.c \ + fetch.h fetch.c \ + helpers.h \ + instruction.h instruction.c \ + link.h link.c \ + operand-int.h \ + operand.h operand.c \ + post.h post.c \ + processor.h processor.c \ + pseudo.h pseudo.c \ + register-int.h \ + register.h register.c \ + thumb_16.h thumb_16.c \ thumb_32.h thumb_32.c -libarmv7_la_LIBADD = \ - opcodes/libarmv7opcodes.la \ - operands/libarmv7operands.la \ +libarmv7_la_LIBADD = \ + opcodes/libarmv7opcodes.la \ + operands/libarmv7operands.la \ registers/libarmv7registers.la +libarmv7_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libarmv7_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - SUBDIRS = opdefs opcodes operands registers diff --git a/plugins/arm/v7/instruction.c b/plugins/arm/v7/instruction.c index 5c2cd98..eb4a082 100644 --- a/plugins/arm/v7/instruction.c +++ b/plugins/arm/v7/instruction.c @@ -90,10 +90,21 @@ static char *g_armv7_instruction_build_tooltip(const GArmV7Instruction *); /* Charge une instruction depuis une mémoire tampon. */ -static bool g_armv7_instruction_unserialize(GArmV7Instruction *, GAsmStorage *, GBinFormat *, packed_buffer *); +static bool g_armv7_instruction_unserialize(GArmV7Instruction *, GAsmStorage *, GBinFormat *, packed_buffer_t *); /* Sauvegarde une instruction dans une mémoire tampon. */ -static bool g_armv7_instruction_serialize(GArmV7Instruction *, GAsmStorage *, packed_buffer *); +static bool g_armv7_instruction_serialize(GArmV7Instruction *, GAsmStorage *, packed_buffer_t *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_armv7_instruction_load(GArmV7Instruction *, GObjectStorage *, packed_buffer_t *); + +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_armv7_instruction_store(GArmV7Instruction *, GObjectStorage *, packed_buffer_t *); @@ -132,6 +143,9 @@ static void g_armv7_instruction_class_init(GArmV7InstructionClass *klass) instr->unserialize = (unserialize_instruction_fc)g_armv7_instruction_unserialize; instr->serialize = (serialize_instruction_fc)g_armv7_instruction_serialize; + instr->load = (load_instruction_fc)g_armv7_instruction_load; + instr->store = (store_instruction_fc)g_armv7_instruction_store; + } @@ -437,7 +451,7 @@ bool g_armv7_instruction_get_setflags(const GArmV7Instruction *instr) * * ******************************************************************************/ -static bool g_armv7_instruction_unserialize(GArmV7Instruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static bool g_armv7_instruction_unserialize(GArmV7Instruction *instr, GAsmStorage *storage, GBinFormat *format, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchInstructionClass *parent; /* Classe parente à consulter */ @@ -481,7 +495,7 @@ static bool g_armv7_instruction_unserialize(GArmV7Instruction *instr, GAsmStorag * * ******************************************************************************/ -static bool g_armv7_instruction_serialize(GArmV7Instruction *instr, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_armv7_instruction_serialize(GArmV7Instruction *instr, GAsmStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchInstructionClass *parent; /* Classe parente à consulter */ @@ -506,3 +520,98 @@ static bool g_armv7_instruction_serialize(GArmV7Instruction *instr, GAsmStorage return result; } + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : instr = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * +* * +* Description : Charge un contenu depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_armv7_instruction_load(GArmV7Instruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchInstructionClass *parent; /* Classe parente à consulter */ + uleb128_t value; /* Valeur ULEB128 à charger */ + uint8_t boolean; /* Valeur booléenne */ + + parent = G_ARCH_INSTRUCTION_CLASS(g_armv7_instruction_parent_class); + + result = parent->load(G_ARCH_INSTRUCTION(instr), storage, pbuf); + + if (result) + result = unpack_uleb128(&value, pbuf); + + if (result) + instr->sid = value; + + if (result) + result = extract_packed_buffer(pbuf, &instr->encoding, sizeof(char), false); + + if (result) + { + result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); + + if (result) + instr->setflags = (boolean == 1 ? true : false); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : instr = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à remplir. * +* * +* Description : Sauvegarde un contenu dans une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_armv7_instruction_store(GArmV7Instruction *instr, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchInstructionClass *parent; /* Classe parente à consulter */ + uint8_t boolean; /* Valeur booléenne */ + + parent = G_ARCH_INSTRUCTION_CLASS(g_armv7_instruction_parent_class); + + result = parent->store(G_ARCH_INSTRUCTION(instr), storage, pbuf); + + if (result) + result = pack_uleb128((uleb128_t []){ instr->sid }, pbuf); + + if (result) + result = extend_packed_buffer(pbuf, &instr->encoding, sizeof(char), false); + + if (result) + { + boolean = (instr->setflags ? 1 : 0); + result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); + } + + return result; + +} diff --git a/plugins/arm/v7/opcodes/Makefile.am b/plugins/arm/v7/opcodes/Makefile.am index 7a35ff9..c7fa4cc 100644 --- a/plugins/arm/v7/opcodes/Makefile.am +++ b/plugins/arm/v7/opcodes/Makefile.am @@ -13,7 +13,7 @@ noinst_LTLIBRARIES = libarmv7opcodes.la libarmv7opcodes_la_SOURCES = $(GENERATED_FILES) -libarmv7opcodes_la_LIBADD = +libarmv7opcodes_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) @@ -21,11 +21,6 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libarmv7opcodes_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) -I$(top_srcdir)/src - - CLEANFILES = $(GENERATED_FILES) dist-hook: diff --git a/plugins/arm/v7/operand-int.h b/plugins/arm/v7/operand-int.h new file mode 100644 index 0000000..1832c32 --- /dev/null +++ b/plugins/arm/v7/operand-int.h @@ -0,0 +1,51 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand-int.h - prototypes pour la définition interne des opérandes ARMv7 + * + * Copyright (C) 2021 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_ARM_V7_OPERAND_INT_H +#define _PLUGINS_ARM_V7_OPERAND_INT_H + + +#include "operand.h" + + +#include <arch/operand-int.h> + + + +/* Définition générique d'un opérande ARMv7 (instance) */ +struct _GArmV7Operand +{ + GArchOperand parent; /* A laisser en premier */ + +}; + +/* Définition générique d'un opérande ARMv7 (classe) */ +struct _GArmV7OperandClass +{ + GArchOperandClass parent; /* A laisser en premier */ + +}; + + + +#endif /* _PLUGINS_ARM_V7_OPERAND_INT_H */ diff --git a/plugins/arm/v7/operand.c b/plugins/arm/v7/operand.c new file mode 100644 index 0000000..ad7b572 --- /dev/null +++ b/plugins/arm/v7/operand.c @@ -0,0 +1,188 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand.c - opérandes ARMv7 + * + * Copyright (C) 2021 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "operand.h" + + +#include "operand-int.h" + + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + +/* Initialise la classe des affichages de boutisme. */ +static void g_armv7_operand_class_init(GArmV7OperandClass *); + +/* Initialise une instance d'affichage de boutisme. */ +static void g_armv7_operand_init(GArmV7Operand *); + +/* Supprime toutes les références externes. */ +static void g_armv7_operand_dispose(GArmV7Operand *); + +/* Procède à la libération totale de la mémoire. */ +static void g_armv7_operand_finalize(GArmV7Operand *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_armv7_operand_hash(const GArmV7Operand *, bool); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini par la GLib pour une de domaine et d'accès. */ +G_DEFINE_TYPE(GArmV7Operand, g_armv7_operand, G_TYPE_ARCH_OPERAND); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des affichages de boutisme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv7_operand_class_init(GArmV7OperandClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GArchOperandClass *operand; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_operand_dispose; + object->finalize = (GObjectFinalizeFunc)g_armv7_operand_finalize; + + operand = G_ARCH_OPERAND_CLASS(klass); + + operand->hash = (operand_hash_fc)g_armv7_operand_hash; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = instance à initialiser. * +* * +* Description : Initialise une instance d'affichage de boutisme. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv7_operand_init(GArmV7Operand *operand) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : operand = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv7_operand_dispose(GArmV7Operand *operand) +{ + G_OBJECT_CLASS(g_armv7_operand_parent_class)->dispose(G_OBJECT(operand)); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv7_operand_finalize(GArmV7Operand *operand) +{ + G_OBJECT_CLASS(g_armv7_operand_parent_class)->finalize(G_OBJECT(operand)); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * +* * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * +* * +* Retour : Empreinte de l'élément représenté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static guint g_armv7_operand_hash(const GArmV7Operand *operand, bool lock) +{ + guint result; /* Valeur à retourner */ + operand_extra_data_t *extra; /* Données insérées à modifier */ + GArchOperandClass *class; /* Classe parente normalisée */ + + extra = GET_ARCH_OP_EXTRA(G_ARCH_OPERAND(operand)); + + if (lock) + LOCK_GOBJECT_EXTRA(extra); + + class = G_ARCH_OPERAND_CLASS(g_armv7_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); + + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} diff --git a/plugins/arm/v7/operand.h b/plugins/arm/v7/operand.h new file mode 100644 index 0000000..8c80365 --- /dev/null +++ b/plugins/arm/v7/operand.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * operand.h - prototypes pour les opérandes ARMv7 + * + * Copyright (C) 2017-2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_ARM_V7_OPERAND_H +#define _PLUGINS_ARM_V7_OPERAND_H + + +#include <glib-object.h> + + +#include <arch/operand.h> + + + +#define G_TYPE_ARMV7_OPERAND g_armv7_operand_get_type() +#define G_ARMV7_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARMV7_OPERAND, GArmV7Operand)) +#define G_IS_ARMV7_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARMV7_OPERAND)) +#define G_ARMV7_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_ARMV7_OPERAND, GArmV7OperandClass)) +#define G_IS_ARMV7_OPERAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_ARMV7_OPERAND)) +#define G_ARMV7_OPERAND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_ARMV7_OPERAND, GArmV7OperandClass)) + + +/* Définition générique d'un opérande ARMv7 (instance) */ +typedef struct _GArmV7Operand GArmV7Operand; + +/* Définition générique d'un opérande ARMv7 (classe) */ +typedef struct _GArmV7OperandClass GArmV7OperandClass; + + +/* Indique le type défini par la GLib pour un opérande ARMv7. */ +GType g_armv7_operand_get_type(void); + + + +#endif /* _PLUGINS_ARM_V7_OPERAND_H */ diff --git a/plugins/arm/v7/operands/Makefile.am b/plugins/arm/v7/operands/Makefile.am index 31f6a8a..fa7ab8b 100644 --- a/plugins/arm/v7/operands/Makefile.am +++ b/plugins/arm/v7/operands/Makefile.am @@ -1,26 +1,21 @@ noinst_LTLIBRARIES = libarmv7operands.la -libarmv7operands_la_SOURCES = \ - estate.h estate.c \ - iflags.h iflags.c \ - it.h it.c \ - limitation.h limitation.c \ - maccess.h maccess.c \ - offset.h offset.c \ - register.h register.c \ - reglist.h reglist.c \ - rotation.h rotation.c \ +libarmv7operands_la_SOURCES = \ + estate.h estate.c \ + iflags.h iflags.c \ + it.h it.c \ + limitation.h limitation.c \ + maccess.h maccess.c \ + offset.h offset.c \ + register.h register.c \ + reglist.h reglist.c \ + rotation.h rotation.c \ shift.h shift.c -libarmv7operands_la_LIBADD = +libarmv7operands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libarmv7operands_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/arm/v7/operands/estate.c b/plugins/arm/v7/operands/estate.c index be6a0ff..accde6d 100644 --- a/plugins/arm/v7/operands/estate.c +++ b/plugins/arm/v7/operands/estate.c @@ -24,18 +24,20 @@ #include "estate.h" -#include <arch/operand-int.h> -#include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> +#include "../operand-int.h" + + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + /* Définition d'un opérande affichant le choix d'un boutisme (instance) */ struct _GArmV7EndianOperand { - GArchOperand parent; /* Instance parente */ - - bool big; /* Grand boutisme à afficher ? */ + GArmV7Operand parent; /* Instance parente */ }; @@ -43,7 +45,7 @@ struct _GArmV7EndianOperand /* Définition d'un opérande affichant le choix d'un boutisme (classe) */ struct _GArmV7EndianOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; @@ -60,27 +62,23 @@ static void g_armv7_endian_operand_dispose(GArmV7EndianOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_endian_operand_finalize(GArmV7EndianOperand *); -/* Compare un opérande avec un autre. */ -static int g_armv7_endian_operand_compare(const GArmV7EndianOperand *, const GArmV7EndianOperand *); -/* Traduit un opérande en version humainement lisible. */ -static void g_armv7_endian_operand_print(const GArmV7EndianOperand *, GBufferLine *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ - +/* Traduit un opérande en version humainement lisible. */ +static void g_armv7_endian_operand_print(const GArmV7EndianOperand *, GBufferLine *); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_endian_operand_unserialize(GArmV7EndianOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_endian_operand_serialize(const GArmV7EndianOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour une endian de domaine et d'accès. */ -G_DEFINE_TYPE(GArmV7EndianOperand, g_armv7_endian_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7EndianOperand, g_armv7_endian_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -106,12 +104,8 @@ static void g_armv7_endian_operand_class_init(GArmV7EndianOperandClass *klass) object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_endian_operand_dispose; object->finalize = (GObjectFinalizeFunc)g_armv7_endian_operand_finalize; - operand->compare = (operand_compare_fc)g_armv7_endian_operand_compare; operand->print = (operand_print_fc)g_armv7_endian_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_endian_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_endian_operand_serialize; - } @@ -173,53 +167,6 @@ static void g_armv7_endian_operand_finalize(GArmV7EndianOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * -* * -* Description : Compare un opérande avec un autre. * -* * -* Retour : Bilan de la comparaison. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int g_armv7_endian_operand_compare(const GArmV7EndianOperand *a, const GArmV7EndianOperand *b) -{ - int result; /* Bilan à faire remonter */ - - result = sort_boolean(a->big, b->big); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à traiter. * -* line = ligne tampon où imprimer l'opérande donné. * -* * -* Description : Traduit un opérande en version humainement lisible. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_armv7_endian_operand_print(const GArmV7EndianOperand *operand, GBufferLine *line) -{ - if (operand->big) - g_buffer_line_append_text(line, DLC_ASSEMBLY, "BE", 2, RTT_KEY_WORD, NULL); - else - g_buffer_line_append_text(line, DLC_ASSEMBLY, "LE", 2, RTT_KEY_WORD, NULL); - -} - - -/****************************************************************************** -* * * Paramètres : big = indication sur le boutisme à représenter. * * * * Description : Crée une représentation de boutisme ARMv7. * @@ -236,107 +183,38 @@ GArchOperand *g_armv7_endian_operand_new(bool big) result = g_object_new(G_TYPE_ARMV7_ENDIAN_OPERAND, NULL); - result->big = big; + if (big) + g_arch_operand_set_flag(G_ARCH_OPERAND(result), A7ESOF_BIG); return G_ARCH_OPERAND(result); } -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Indique le type de boutisme représenté. * -* * -* Retour : Type de boutisme. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_armv7_endian_operand_is_big_endian(const GArmV7EndianOperand *operand) -{ - return operand->big; - -} - - /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un opérande depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_armv7_endian_operand_unserialize(GArmV7EndianOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) -{ - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t big; /* Grand boutisme à afficher ? */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_endian_operand_parent_class); - - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); - - if (result) - { - result = extract_packed_buffer(pbuf, &big, sizeof(uint8_t), false); - - if (result) - operand->big = (big == 1 ? true : false); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = opérande à traiter. * +* line = ligne tampon où imprimer l'opérande donné. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Traduit un opérande en version humainement lisible. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_endian_operand_serialize(const GArmV7EndianOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static void g_armv7_endian_operand_print(const GArmV7EndianOperand *operand, GBufferLine *line) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t big; /* Grand boutisme à afficher ? */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_endian_operand_parent_class); - - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); - - if (result) - { - big = (operand->big ? 1 : 0); - result = extend_packed_buffer(pbuf, &big, sizeof(uint8_t), false); - } - - return result; + if (g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7ESOF_BIG)) + g_buffer_line_append_text(line, DLC_ASSEMBLY, "BE", 2, RTT_KEY_WORD, NULL); + else + g_buffer_line_append_text(line, DLC_ASSEMBLY, "LE", 2, RTT_KEY_WORD, NULL); } diff --git a/plugins/arm/v7/operands/estate.h b/plugins/arm/v7/operands/estate.h index d049357..9b75f9c 100644 --- a/plugins/arm/v7/operands/estate.h +++ b/plugins/arm/v7/operands/estate.h @@ -32,6 +32,14 @@ +/* Etats particuliers d'un opérande de valeur immédiate */ +typedef enum _A7EStateOpFlag +{ + A7ESOF_BIG = AOF_USER_FLAG(0), /* Grand boutisme à afficher ? */ + +} A7EStateOpFlag; + + #define G_TYPE_ARMV7_ENDIAN_OPERAND g_armv7_endian_operand_get_type() #define G_ARMV7_ENDIAN_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARMV7_ENDIAN_OPERAND, GArmV7EndianOperand)) #define G_IS_ARMV7_ENDIAN_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARMV7_ENDIAN_OPERAND)) @@ -53,9 +61,6 @@ GType g_armv7_endian_operand_get_type(void); /* Crée une représentation de boutisme ARMv7. */ GArchOperand *g_armv7_endian_operand_new(bool); -/* Indique le type de boutisme représenté. */ -bool g_armv7_endian_operand_is_big_endian(const GArmV7EndianOperand *); - #endif /* _PLUGINS_ARM_V7_OPERANDS_ESTATE_H */ diff --git a/plugins/arm/v7/operands/iflags.c b/plugins/arm/v7/operands/iflags.c index ff073c6..f0a5e07 100644 --- a/plugins/arm/v7/operands/iflags.c +++ b/plugins/arm/v7/operands/iflags.c @@ -24,19 +24,20 @@ #include "iflags.h" -#include <arch/operand-int.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> +#include "../operand-int.h" + + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + /* Définition d'un opérande précisant un masque d'interruption ARMv7 (instance) */ struct _GArmV7IFlagsOperand { - GArchOperand parent; /* Instance parente */ - - bool abort_bit; /* Interruption d'arrêt async. */ - bool irq_bit; /* Interruption IRQ */ - bool fiq_bit; /* Interruption FIQ */ + GArmV7Operand parent; /* Instance parente */ }; @@ -44,7 +45,7 @@ struct _GArmV7IFlagsOperand /* Définition d'un opérande précisant un masque d'interruption ARMv7 (classe) */ struct _GArmV7IFlagsOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; @@ -61,24 +62,22 @@ static void g_armv7_iflags_operand_dispose(GArmV7IFlagsOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_iflags_operand_finalize(GArmV7IFlagsOperand *); -/* Traduit un opérande en version humainement lisible. */ -static void g_armv7_iflags_operand_print(const GArmV7IFlagsOperand *, GBufferLine *); - -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Traduit un opérande en version humainement lisible. */ +static void g_armv7_iflags_operand_print(const GArmV7IFlagsOperand *, GBufferLine *); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_iflags_operand_unserialize(GArmV7IFlagsOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_iflags_operand_serialize(const GArmV7IFlagsOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un opérande de masque d'interruption ARMv7. */ -G_DEFINE_TYPE(GArmV7IFlagsOperand, g_armv7_iflags_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7IFlagsOperand, g_armv7_iflags_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -107,9 +106,6 @@ static void g_armv7_iflags_operand_class_init(GArmV7IFlagsOperandClass *klass) operand->print = (operand_print_fc)g_armv7_iflags_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_iflags_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_iflags_operand_serialize; - } @@ -127,9 +123,6 @@ static void g_armv7_iflags_operand_class_init(GArmV7IFlagsOperandClass *klass) static void g_armv7_iflags_operand_init(GArmV7IFlagsOperand *operand) { - operand->abort_bit = false; - operand->irq_bit = false; - operand->fiq_bit = false; } @@ -174,33 +167,6 @@ static void g_armv7_iflags_operand_finalize(GArmV7IFlagsOperand *operand) /****************************************************************************** * * -* Paramètres : operand = opérande à traiter. * -* line = ligne tampon où imprimer l'opérande donné. * -* * -* Description : Traduit un opérande en version humainement lisible. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_armv7_iflags_operand_print(const GArmV7IFlagsOperand *operand, GBufferLine *line) -{ - if (operand->abort_bit) - g_buffer_line_append_text(line, DLC_ASSEMBLY, "A", 1, RTT_REGISTER, NULL); - - if (operand->irq_bit) - g_buffer_line_append_text(line, DLC_ASSEMBLY, "I", 1, RTT_REGISTER, NULL); - - if (operand->fiq_bit) - g_buffer_line_append_text(line, DLC_ASSEMBLY, "F", 1, RTT_REGISTER, NULL); - -} - - -/****************************************************************************** -* * * Paramètres : a = bit d'arrêt asynchrone. * * i = bit d'interruption IRQ. * * f = bit d'interruption FIQ. * @@ -219,119 +185,48 @@ GArchOperand *g_armv7_iflags_operand_new(bool a, bool i, bool f) result = g_object_new(G_TYPE_ARMV7_IFLAGS_OPERAND, NULL); - result->abort_bit = a; - result->irq_bit = i; - result->fiq_bit = f; + if (a) + g_arch_operand_set_flag(G_ARCH_OPERAND(result), A7IFOF_ABORT); + + if (i) + g_arch_operand_set_flag(G_ARCH_OPERAND(result), A7IFOF_IRQ); + + if (f) + g_arch_operand_set_flag(G_ARCH_OPERAND(result), A7IFOF_FIQ); return G_ARCH_OPERAND(result); } + /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un opérande depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_armv7_iflags_operand_unserialize(GArmV7IFlagsOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) -{ - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t boolean; /* Valeur booléenne */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_iflags_operand_parent_class); - - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); - - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result) - operand->abort_bit = (boolean == 1 ? true : false); - - } - - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result) - operand->irq_bit = (boolean == 1 ? true : false); - - } - - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result) - operand->fiq_bit = (boolean == 1 ? true : false); - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = opérande à traiter. * +* line = ligne tampon où imprimer l'opérande donné. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Traduit un opérande en version humainement lisible. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_iflags_operand_serialize(const GArmV7IFlagsOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static void g_armv7_iflags_operand_print(const GArmV7IFlagsOperand *operand, GBufferLine *line) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t boolean; /* Valeur booléenne */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_iflags_operand_parent_class); - - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); - - if (result) - { - boolean = (operand->abort_bit ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } - - if (result) - { - boolean = (operand->irq_bit ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } + if (g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7IFOF_ABORT)) + g_buffer_line_append_text(line, DLC_ASSEMBLY, "A", 1, RTT_REGISTER, NULL); - if (result) - { - boolean = (operand->fiq_bit ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } + if (g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7IFOF_IRQ)) + g_buffer_line_append_text(line, DLC_ASSEMBLY, "I", 1, RTT_REGISTER, NULL); - return result; + if (g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7IFOF_FIQ)) + g_buffer_line_append_text(line, DLC_ASSEMBLY, "F", 1, RTT_REGISTER, NULL); } diff --git a/plugins/arm/v7/operands/iflags.h b/plugins/arm/v7/operands/iflags.h index c0155a1..a198c85 100644 --- a/plugins/arm/v7/operands/iflags.h +++ b/plugins/arm/v7/operands/iflags.h @@ -33,6 +33,16 @@ +/* Etats particuliers d'un opérande de valeur immédiate */ +typedef enum _A7IFlagsOpFlag +{ + A7IFOF_ABORT = AOF_USER_FLAG(0), /* Interruption d'arrêt async. */ + A7IFOF_IRQ = AOF_USER_FLAG(1), /* Interruption IRQ */ + A7IFOF_FIQ = AOF_USER_FLAG(2), /* Interruption FIQ */ + +} A7IFlagsOpFlag; + + #define G_TYPE_ARMV7_IFLAGS_OPERAND g_armv7_iflags_operand_get_type() #define G_ARMV7_IFLAGS_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARMV7_IFLAGS_OPERAND, GArmV7IFlagsOperand)) #define G_IS_ARMV7_IFLAGS_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARMV7_IFLAGS_OPERAND)) diff --git a/plugins/arm/v7/operands/it.c b/plugins/arm/v7/operands/it.c index e40b52a..46e1b4c 100644 --- a/plugins/arm/v7/operands/it.c +++ b/plugins/arm/v7/operands/it.c @@ -27,27 +27,55 @@ #include <assert.h> -#include <arch/operand-int.h> #include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> +#include "../operand-int.h" -/* Définition d'un opérande organisant l'application d'une instruction IT (instance) */ -struct _GArmV7ITCondOperand + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _a7itcop_extra_data_t { - GArchOperand parent; /* Instance parente */ + operand_extra_data_t parent; /* A laisser en premier */ ArmCondCode firstcond; /* Condition première */ uint8_t mask; /* Masque de l'interprétation */ +} a7itcop_extra_data_t; + + +/* Définition d'un opérande organisant l'application d'une instruction IT (instance) */ +struct _GArmV7ITCondOperand +{ + GArmV7Operand parent; /* Instance parente */ + }; +/** + * Accès aux informations éventuellement déportées. + */ + +#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + +# define GET_ARMV7_ITCOND_OP_EXTRA(op) ((a7itcop_extra_data_t *)&((GArchOperand *)op)->extra) + +#else + +# define GET_ARMV7_ITCOND_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), a7itcop_extra_data_t) + +#endif + + /* Définition d'un opérande organisant l'application d'une instruction IT (classe) */ struct _GArmV7ITCondOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; @@ -64,27 +92,35 @@ static void g_armv7_itcond_operand_dispose(GArmV7ITCondOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_itcond_operand_finalize(GArmV7ITCondOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_armv7_itcond_operand_compare(const GArmV7ITCondOperand *, const GArmV7ITCondOperand *); +static int g_armv7_itcond_operand_compare(const GArmV7ITCondOperand *, const GArmV7ITCondOperand *, bool); /* Traduit un opérande en version humainement lisible. */ static void g_armv7_itcond_operand_print(const GArmV7ITCondOperand *, GBufferLine *); +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_armv7_itcond_operand_hash(const GArmV7ITCondOperand *, bool); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_armv7_itcond_operand_load(GArmV7ITCondOperand *, GObjectStorage *, packed_buffer_t *); -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_armv7_itcond_operand_store(GArmV7ITCondOperand *, GObjectStorage *, packed_buffer_t *); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_itcond_operand_unserialize(GArmV7ITCondOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); - -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_itcond_operand_serialize(const GArmV7ITCondOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour l'application d'une instruction IT. */ -G_DEFINE_TYPE(GArmV7ITCondOperand, g_armv7_itcond_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7ITCondOperand, g_armv7_itcond_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -105,16 +141,20 @@ static void g_armv7_itcond_operand_class_init(GArmV7ITCondOperandClass *klass) GArchOperandClass *operand; /* Version de classe parente */ object = G_OBJECT_CLASS(klass); - operand = G_ARCH_OPERAND_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_itcond_operand_dispose; object->finalize = (GObjectFinalizeFunc)g_armv7_itcond_operand_finalize; + operand = G_ARCH_OPERAND_CLASS(klass); + operand->compare = (operand_compare_fc)g_armv7_itcond_operand_compare; + operand->print = (operand_print_fc)g_armv7_itcond_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_itcond_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_itcond_operand_serialize; + operand->hash = (operand_hash_fc)g_armv7_itcond_operand_hash; + + operand->load = (load_operand_fc)g_armv7_itcond_operand_load; + operand->store = (store_operand_fc)g_armv7_itcond_operand_store; } @@ -177,8 +217,100 @@ static void g_armv7_itcond_operand_finalize(GArmV7ITCondOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : firstcond = valeur brute de la condition d'exécution. * +* mask = masque d'interprétation pour l'instruction. * +* * +* Description : Crée un opérande lié à une instruction IT. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_itcond_operand_new(uint8_t firstcond, uint8_t mask) +{ + GArmV7ITCondOperand *result; /* Structure à retourner */ + a7itcop_extra_data_t *extra; /* Données insérées à modifier */ + + if (firstcond > ACC_NV) + return NULL; + + result = g_object_new(G_TYPE_ARMV7_ITCOND_OPERAND, NULL); + + extra = GET_ARMV7_ITCOND_OP_EXTRA(result); + + extra->firstcond = firstcond; + extra->mask = mask; + + return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Fournit la condition associée à l'opérande. * +* * +* Retour : Condition classique pour ARMv7. * +* * +* Remarques : - * +* * +******************************************************************************/ + +ArmCondCode g_armv7_itcond_operand_get_firstcond(const GArmV7ITCondOperand *operand) +{ + ArmCondCode result; /* Condition à renvoyer */ + a7itcop_extra_data_t *extra; /* Données insérées à modifier */ + + extra = GET_ARMV7_ITCOND_OP_EXTRA(operand); + + result = extra->firstcond; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Fournit le masque d'interprétation de la condition. * +* * +* Retour : Masque de bits. * +* * +* Remarques : - * +* * +******************************************************************************/ + +uint8_t g_armv7_itcond_operand_get_mask(const GArmV7ITCondOperand *operand) +{ + uint8_t result; /* Valeur à retourner */ + a7itcop_extra_data_t *extra; /* Données insérées à modifier */ + + extra = GET_ARMV7_ITCOND_OP_EXTRA(operand); + + result = extra->mask; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -188,14 +320,38 @@ static void g_armv7_itcond_operand_finalize(GArmV7ITCondOperand *operand) * * ******************************************************************************/ -static int g_armv7_itcond_operand_compare(const GArmV7ITCondOperand *a, const GArmV7ITCondOperand *b) +static int g_armv7_itcond_operand_compare(const GArmV7ITCondOperand *a, const GArmV7ITCondOperand *b, bool lock) { int result; /* Bilan à faire remonter */ + a7itcop_extra_data_t *ea; /* Données insérées à consulter*/ + a7itcop_extra_data_t *eb; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + + ea = GET_ARMV7_ITCOND_OP_EXTRA(a); + eb = GET_ARMV7_ITCOND_OP_EXTRA(b); + + if (lock) + { + LOCK_GOBJECT_EXTRA(ea); + LOCK_GOBJECT_EXTRA(eb); + } + + result = sort_boolean(ea->firstcond, eb->firstcond); - result = sort_boolean(a->firstcond, b->firstcond); + if (result == 0) + result = sort_unsigned_long(ea->mask, eb->mask); if (result == 0) - result = sort_unsigned_long(a->mask, b->mask); + { + class = G_ARCH_OPERAND_CLASS(g_armv7_itcond_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } + + if (lock) + { + UNLOCK_GOBJECT_EXTRA(eb); + UNLOCK_GOBJECT_EXTRA(ea); + } return result; @@ -217,9 +373,12 @@ static int g_armv7_itcond_operand_compare(const GArmV7ITCondOperand *a, const GA static void g_armv7_itcond_operand_print(const GArmV7ITCondOperand *operand, GBufferLine *line) { + a7itcop_extra_data_t *extra; /* Données insérées à consulter*/ const char *kw; /* Mot clef à imprimer */ - switch (operand->firstcond) + extra = GET_ARMV7_ITCOND_OP_EXTRA(operand); + + switch (extra->firstcond) { case ACC_EQ: kw = "EQ"; break; case ACC_NE: kw = "NE"; break; @@ -253,51 +412,37 @@ static void g_armv7_itcond_operand_print(const GArmV7ITCondOperand *operand, GBu /****************************************************************************** * * -* Paramètres : firstcond = valeur brute de la condition d'exécution. * -* mask = masque d'interprétation pour l'instruction. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * * * -* Description : Crée un opérande lié à une instruction IT. * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * * * -* Retour : Opérande mis en place. * +* Retour : Empreinte de l'élément représenté. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_armv7_itcond_operand_new(uint8_t firstcond, uint8_t mask) +static guint g_armv7_itcond_operand_hash(const GArmV7ITCondOperand *operand, bool lock) { - GArmV7ITCondOperand *result; /* Structure à retourner */ + guint result; /* Valeur à retourner */ + a7itcop_extra_data_t *extra; /* Données internes à manipuler*/ + GArchOperandClass *class; /* Classe parente normalisée */ - if (firstcond > ACC_NV) - return NULL; + extra = GET_ARMV7_ITCOND_OP_EXTRA(operand); - result = g_object_new(G_TYPE_ARMV7_ITCOND_OPERAND, NULL); + if (lock) + LOCK_GOBJECT_EXTRA(extra); - result->firstcond = firstcond; - result->mask = mask; + class = G_ARCH_OPERAND_CLASS(g_armv7_itcond_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); - return G_ARCH_OPERAND(result); + result ^= extra->firstcond; -} + result ^= extra->mask; - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Fournit la condition associée à l'opérande. * -* * -* Retour : Condition classique pour ARMv7. * -* * -* Remarques : - * -* * -******************************************************************************/ - -ArmCondCode g_armv7_itcond_operand_get_firstcond(const GArmV7ITCondOperand *operand) -{ - ArmCondCode result; /* Condition à renvoyer */ - - result = operand->firstcond; + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); return result; @@ -306,41 +451,11 @@ ArmCondCode g_armv7_itcond_operand_get_firstcond(const GArmV7ITCondOperand *oper /****************************************************************************** * * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Fournit le masque d'interprétation de la condition. * -* * -* Retour : Masque de bits. * +* Paramètres : operand = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * * * -* Remarques : - * -* * -******************************************************************************/ - -uint8_t g_armv7_itcond_operand_get_mask(const GArmV7ITCondOperand *operand) -{ - uint8_t result; /* Valeur à retourner */ - - result = operand->mask; - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un opérande depuis une mémoire tampon. * +* Description : Charge un contenu depuis une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -348,20 +463,30 @@ uint8_t g_armv7_itcond_operand_get_mask(const GArmV7ITCondOperand *operand) * * ******************************************************************************/ -static bool g_armv7_itcond_operand_unserialize(GArmV7ITCondOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static bool g_armv7_itcond_operand_load(GArmV7ITCondOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ + uleb128_t value; /* Valeur ULEB128 à charger */ + a7itcop_extra_data_t *extra; /* Données insérées à modifier */ parent = G_ARCH_OPERAND_CLASS(g_armv7_itcond_operand_parent_class); - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); + result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); if (result) - result = extract_packed_buffer(pbuf, &operand->firstcond, sizeof(ArmCondCode), true); + { + extra = GET_ARMV7_ITCOND_OP_EXTRA(operand); - if (result) - result = extract_packed_buffer(pbuf, &operand->mask, sizeof(uint8_t), false); + result = unpack_uleb128(&value, pbuf); + + if (result) + extra->firstcond = value; + + if (result) + result = extract_packed_buffer(pbuf, &extra->mask, sizeof(uint8_t), false); + + } return result; @@ -370,11 +495,11 @@ static bool g_armv7_itcond_operand_unserialize(GArmV7ITCondOperand *operand, GAs /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : operand = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -382,20 +507,26 @@ static bool g_armv7_itcond_operand_unserialize(GArmV7ITCondOperand *operand, GAs * * ******************************************************************************/ -static bool g_armv7_itcond_operand_serialize(const GArmV7ITCondOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_armv7_itcond_operand_store(GArmV7ITCondOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ + a7itcop_extra_data_t *extra; /* Données insérées à modifier */ parent = G_ARCH_OPERAND_CLASS(g_armv7_itcond_operand_parent_class); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); if (result) - result = extend_packed_buffer(pbuf, &operand->firstcond, sizeof(ArmCondCode), true); + { + extra = GET_ARMV7_ITCOND_OP_EXTRA(operand); - if (result) - result = extend_packed_buffer(pbuf, &operand->mask, sizeof(uint8_t), false); + result = pack_uleb128((uleb128_t []){ extra->firstcond }, pbuf); + + if (result) + result = extend_packed_buffer(pbuf, &extra->mask, sizeof(uint8_t), false); + + } return result; diff --git a/plugins/arm/v7/operands/limitation.c b/plugins/arm/v7/operands/limitation.c index 5663aba..d9e11cf 100644 --- a/plugins/arm/v7/operands/limitation.c +++ b/plugins/arm/v7/operands/limitation.c @@ -26,28 +26,57 @@ #include <arch/operand-int.h> #include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> +#include "../operand-int.h" -/* Définition d'un opérande déterminant une limitation de domaine et d'accès (instance) */ -struct _GArmV7LimitationOperand + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _a7limop_extra_data_t { - GArchOperand parent; /* Instance parente */ + operand_extra_data_t parent; /* A laisser en premier */ BarrierLimitationType type; /* Type de limitation */ +} a7limop_extra_data_t; + + +/* Définition d'un opérande déterminant une limitation de domaine et d'accès (instance) */ +struct _GArmV7LimitationOperand +{ + GArmV7Operand parent; /* Instance parente */ + }; /* Définition d'un opérande déterminant une limitation de domaine et d'accès (classe) */ struct _GArmV7LimitationOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; +/** + * Accès aux informations éventuellement déportées. + */ + +#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + +# define GET_ARMV7_LIMITATION_OP_EXTRA(op) ((a7limop_extra_data_t *)&((GArchOperand *)op)->extra) + +#else + +# define GET_ARMV7_LIMITATION_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), a7limop_extra_data_t) + +#endif + + /* Initialise la classe des co-processeurs ARM. */ static void g_armv7_limitation_operand_class_init(GArmV7LimitationOperandClass *); @@ -60,27 +89,35 @@ static void g_armv7_limitation_operand_dispose(GArmV7LimitationOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_limitation_operand_finalize(GArmV7LimitationOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_armv7_limitation_operand_compare(const GArmV7LimitationOperand *, const GArmV7LimitationOperand *); +static int g_armv7_limitation_operand_compare(const GArmV7LimitationOperand *, const GArmV7LimitationOperand *, bool); /* Traduit un opérande en version humainement lisible. */ static void g_armv7_limitation_operand_print(const GArmV7LimitationOperand *, GBufferLine *); +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_armv7_limitation_operand_hash(const GArmV7LimitationOperand *, bool); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_armv7_limitation_operand_load(GArmV7LimitationOperand *, GObjectStorage *, packed_buffer_t *); -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ - +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_armv7_limitation_operand_store(GArmV7LimitationOperand *, GObjectStorage *, packed_buffer_t *); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_limitation_operand_unserialize(GArmV7LimitationOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_limitation_operand_serialize(const GArmV7LimitationOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour une limitation de domaine et d'accès. */ -G_DEFINE_TYPE(GArmV7LimitationOperand, g_armv7_limitation_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7LimitationOperand, g_armv7_limitation_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -107,10 +144,13 @@ static void g_armv7_limitation_operand_class_init(GArmV7LimitationOperandClass * object->finalize = (GObjectFinalizeFunc)g_armv7_limitation_operand_finalize; operand->compare = (operand_compare_fc)g_armv7_limitation_operand_compare; + operand->print = (operand_print_fc)g_armv7_limitation_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_limitation_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_limitation_operand_serialize; + operand->hash = (operand_hash_fc)g_armv7_limitation_operand_hash; + + operand->load = (load_operand_fc)g_armv7_limitation_operand_load; + operand->store = (store_operand_fc)g_armv7_limitation_operand_store; } @@ -173,8 +213,77 @@ static void g_armv7_limitation_operand_finalize(GArmV7LimitationOperand *operand /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : raw = valeur brute de la limitation à considérer. * +* * +* Description : Crée une représentation d'une limitation pour barrière. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_limitation_operand_new(uint8_t raw) +{ + GArmV7LimitationOperand *result; /* Structure à retourner */ + a7limop_extra_data_t *extra; /* Données insérées à modifier */ + + result = g_object_new(G_TYPE_ARMV7_LIMITATION_OPERAND, NULL); + + extra = GET_ARMV7_LIMITATION_OP_EXTRA(result); + + if (raw < 0b0010 || raw > 0b1111) + extra->type = BLT_RESERVED; + + else + extra->type = raw; + + return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Indique le type de limitation représentée. * +* * +* Retour : Type de limitation d'accès et de domaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +BarrierLimitationType g_armv7_limitation_operand_get_value(const GArmV7LimitationOperand *operand) +{ + BarrierLimitationType result; /* Type à retourner */ + a7limop_extra_data_t *extra; /* Données insérées à consulter*/ + + extra = GET_ARMV7_LIMITATION_OP_EXTRA(operand); + + LOCK_GOBJECT_EXTRA(extra); + + result = extra->type; + + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -184,11 +293,35 @@ static void g_armv7_limitation_operand_finalize(GArmV7LimitationOperand *operand * * ******************************************************************************/ -static int g_armv7_limitation_operand_compare(const GArmV7LimitationOperand *a, const GArmV7LimitationOperand *b) +static int g_armv7_limitation_operand_compare(const GArmV7LimitationOperand *a, const GArmV7LimitationOperand *b, bool lock) { int result; /* Bilan à faire remonter */ + a7limop_extra_data_t *ea; /* Données insérées à consulter*/ + a7limop_extra_data_t *eb; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ - result = sort_unsigned_long(a->type, b->type); + ea = GET_ARMV7_LIMITATION_OP_EXTRA(a); + eb = GET_ARMV7_LIMITATION_OP_EXTRA(b); + + if (lock) + { + LOCK_GOBJECT_EXTRA(ea); + LOCK_GOBJECT_EXTRA(eb); + } + + result = sort_unsigned_long(ea->type, eb->type); + + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_armv7_limitation_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } + + if (lock) + { + UNLOCK_GOBJECT_EXTRA(eb); + UNLOCK_GOBJECT_EXTRA(ea); + } return result; @@ -210,7 +343,11 @@ static int g_armv7_limitation_operand_compare(const GArmV7LimitationOperand *a, static void g_armv7_limitation_operand_print(const GArmV7LimitationOperand *operand, GBufferLine *line) { - switch (operand->type) + BarrierLimitationType type; /* Type porté par l'opérande */ + + type = g_armv7_limitation_operand_get_value(operand); + + switch (type) { case BLT_SY: g_buffer_line_append_text(line, DLC_ASSEMBLY, "SY", 2, RTT_KEY_WORD, NULL); @@ -255,66 +392,48 @@ static void g_armv7_limitation_operand_print(const GArmV7LimitationOperand *oper /****************************************************************************** * * -* Paramètres : raw = valeur brute de la limitation à considérer. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * * * -* Description : Crée une représentation d'une limitation pour barrière. * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * * * -* Retour : Opérande mis en place. * +* Retour : Empreinte de l'élément représenté. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_armv7_limitation_operand_new(uint8_t raw) +static guint g_armv7_limitation_operand_hash(const GArmV7LimitationOperand *operand, bool lock) { - GArmV7LimitationOperand *result; /* Structure à retourner */ + guint result; /* Valeur à retourner */ + a7limop_extra_data_t *extra; /* Données internes à manipuler*/ + GArchOperandClass *class; /* Classe parente normalisée */ - result = g_object_new(G_TYPE_ARMV7_LIMITATION_OPERAND, NULL); + extra = GET_ARMV7_LIMITATION_OP_EXTRA(operand); - if (raw < 0b0010 || raw > 0b1111) - result->type = BLT_RESERVED; + if (lock) + LOCK_GOBJECT_EXTRA(extra); - else - result->type = raw; + class = G_ARCH_OPERAND_CLASS(g_armv7_limitation_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); - return G_ARCH_OPERAND(result); + result ^= extra->type; -} + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Indique le type de limitation représentée. * -* * -* Retour : Type de limitation d'accès et de domaine. * -* * -* Remarques : - * -* * -******************************************************************************/ - -BarrierLimitationType g_armv7_limitation_operand_get_value(const GArmV7LimitationOperand *operand) -{ - return operand->type; + return result; } - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * * * -* Description : Charge un opérande depuis une mémoire tampon. * +* Description : Charge un contenu depuis une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -322,17 +441,27 @@ BarrierLimitationType g_armv7_limitation_operand_get_value(const GArmV7Limitatio * * ******************************************************************************/ -static bool g_armv7_limitation_operand_unserialize(GArmV7LimitationOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static bool g_armv7_limitation_operand_load(GArmV7LimitationOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ + a7limop_extra_data_t *extra; /* Données insérées à modifier */ + uleb128_t value; /* Valeur ULEB128 à charger */ parent = G_ARCH_OPERAND_CLASS(g_armv7_limitation_operand_parent_class); - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); + result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); if (result) - result = extract_packed_buffer(pbuf, &operand->type, sizeof(BarrierLimitationType), true); + { + extra = GET_ARMV7_LIMITATION_OP_EXTRA(operand); + + result = unpack_uleb128(&value, pbuf); + + if (result) + extra->type = value; + + } return result; @@ -341,11 +470,11 @@ static bool g_armv7_limitation_operand_unserialize(GArmV7LimitationOperand *oper /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : operand = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -353,17 +482,23 @@ static bool g_armv7_limitation_operand_unserialize(GArmV7LimitationOperand *oper * * ******************************************************************************/ -static bool g_armv7_limitation_operand_serialize(const GArmV7LimitationOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_armv7_limitation_operand_store(GArmV7LimitationOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ + a7limop_extra_data_t *extra; /* Données insérées à modifier */ parent = G_ARCH_OPERAND_CLASS(g_armv7_limitation_operand_parent_class); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); if (result) - result = extend_packed_buffer(pbuf, &operand->type, sizeof(BarrierLimitationType), true); + { + extra = GET_ARMV7_LIMITATION_OP_EXTRA(operand); + + result = pack_uleb128((uleb128_t []){ extra->type }, pbuf); + + } return result; diff --git a/plugins/arm/v7/operands/maccess.c b/plugins/arm/v7/operands/maccess.c index aa0e9cf..77d031f 100644 --- a/plugins/arm/v7/operands/maccess.c +++ b/plugins/arm/v7/operands/maccess.c @@ -29,24 +29,26 @@ #include <stdlib.h> -#include <arch/operand-int.h> #include <common/cpp.h> -#include <common/sort.h> +#include <core/columns.h> #include <core/logs.h> -#include <gtkext/gtkblockdisplay.h> +#include "../operand-int.h" + + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + /* Définition d'un opérande offrant un accès à la mémoire depuis une base (instance) */ struct _GArmV7MAccessOperand { - GArchOperand parent; /* Instance parente */ + GArmV7Operand parent; /* Instance parente */ GArchOperand *base; /* Base de l'accès en mémoire */ GArchOperand *offset; /* Décalage pour l'adresse */ GArchOperand *shift; /* Décalage supplémentaire ? */ - bool post_indexed; /* Position du décalage */ - bool write_back; /* Mise à jour de la base */ }; @@ -54,7 +56,7 @@ struct _GArmV7MAccessOperand /* Définition d'un opérande offrant un accès à la mémoire depuis une base (classe) */ struct _GArmV7MAccessOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; @@ -71,8 +73,13 @@ static void g_armv7_maccess_operand_dispose(GArmV7MAccessOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_maccess_operand_finalize(GArmV7MAccessOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_armv7_maccess_operand_compare(const GArmV7MAccessOperand *, const GArmV7MAccessOperand *); +static int g_armv7_maccess_operand_compare(const GArmV7MAccessOperand *, const GArmV7MAccessOperand *, bool); /* Détermine le chemin conduisant à un opérande interne. */ static char *g_armv7_maccess_operand_find_inner_operand_path(const GArmV7MAccessOperand *, const GArchOperand *); @@ -83,21 +90,24 @@ static GArchOperand *g_armv7_maccess_operand_get_inner_operand_from_path(const G /* Traduit un opérande en version humainement lisible. */ static void g_armv7_maccess_operand_print(const GArmV7MAccessOperand *, GBufferLine *); +/* Fournit une liste de candidats embarqués par un candidat. */ +static GArchOperand **g_armv7_maccess_operand_list_inner_instances(const GArmV7MAccessOperand *, size_t *); +/* Met à jour une liste de candidats embarqués par un candidat. */ +static void g_armv7_maccess_operand_update_inner_instances(GArmV7MAccessOperand *, GArchOperand **, size_t); -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_armv7_maccess_operand_hash(const GArmV7MAccessOperand *, bool); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_maccess_operand_unserialize(GArmV7MAccessOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); - -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_maccess_operand_serialize(const GArmV7MAccessOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un accès à la mémoire depuis une base. */ -G_DEFINE_TYPE(GArmV7MAccessOperand, g_armv7_maccess_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7MAccessOperand, g_armv7_maccess_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -130,8 +140,12 @@ static void g_armv7_maccess_operand_class_init(GArmV7MAccessOperandClass *klass) operand->print = (operand_print_fc)g_armv7_maccess_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_maccess_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_maccess_operand_serialize; + operand->list_inner = (operand_list_inners_fc)g_armv7_maccess_operand_list_inner_instances; + operand->update_inner = (operand_update_inners_fc)g_armv7_maccess_operand_update_inner_instances; + operand->hash = (operand_hash_fc)g_armv7_maccess_operand_hash; + + operand->load = g_arch_operand_load_generic_fixed_3; + operand->store = g_arch_operand_store_generic_fixed; } @@ -171,14 +185,9 @@ static void g_armv7_maccess_operand_init(GArmV7MAccessOperand *operand) static void g_armv7_maccess_operand_dispose(GArmV7MAccessOperand *operand) { - if (operand->base != NULL) - g_object_unref(G_OBJECT(operand->base)); - - if (operand->offset != NULL) - g_object_unref(G_OBJECT(operand->offset)); - - if (operand->shift != NULL) - g_object_unref(G_OBJECT(operand->shift)); + g_clear_object(&operand->base); + g_clear_object(&operand->offset); + g_clear_object(&operand->shift); G_OBJECT_CLASS(g_armv7_maccess_operand_parent_class)->dispose(G_OBJECT(operand)); @@ -206,8 +215,109 @@ static void g_armv7_maccess_operand_finalize(GArmV7MAccessOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : base = représente le registre de la base d'accès. * +* offset = détermine le décalage entre l'adresse et la base. * +* shift = opération de décalage pour jouer sur le décalage. * +* post = précise la forme donnée au décalage à appliquer. * +* wback = indique une mise à jour de la base après usage. * +* * +* Description : Crée un accès à la mémoire depuis une base et un décalage. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_maccess_operand_new(GArchOperand *base, GArchOperand *offset, GArchOperand *shift, bool post, bool wback) +{ + GArmV7MAccessOperand *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_ARMV7_MACCESS_OPERAND, NULL); + + result->base = base; + result->offset = offset; + result->shift = shift; + + if (post) + g_arch_operand_set_flag(G_ARCH_OPERAND(result), A7MAOF_POST_INDEXED); + + if (wback) + g_arch_operand_set_flag(G_ARCH_OPERAND(result), A7MAOF_WRITE_BACK); + + return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Founit la base d'un accès à la mémoire. * +* * +* Retour : Opérande en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_maccess_operand_get_base(const GArmV7MAccessOperand *operand) +{ + return operand->base; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Founit le décalage d'un accès à la mémoire depuis la base. * +* * +* Retour : Opérande en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_maccess_operand_get_offset(const GArmV7MAccessOperand *operand) +{ + return operand->offset; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Founit le décalage d'un décalage pour un accès mémoire. * +* * +* Retour : Opérande en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_maccess_operand_get_shift(const GArmV7MAccessOperand *operand) +{ + return operand->shift; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -217,25 +327,24 @@ static void g_armv7_maccess_operand_finalize(GArmV7MAccessOperand *operand) * * ******************************************************************************/ -static int g_armv7_maccess_operand_compare(const GArmV7MAccessOperand *a, const GArmV7MAccessOperand *b) +static int g_armv7_maccess_operand_compare(const GArmV7MAccessOperand *a, const GArmV7MAccessOperand *b, bool lock) { int result; /* Bilan à faire remonter */ + GArchOperandClass *class; /* Classe parente normalisée */ result = g_arch_operand_compare(a->base, b->base); - if (result != 0) goto gamoc_done; - - result = sort_pointer(a->offset, b->offset, (__compar_fn_t)g_arch_operand_compare); - if (result != 0) goto gamoc_done; - - result = sort_pointer(a->shift, b->shift, (__compar_fn_t)g_arch_operand_compare); - if (result != 0) goto gamoc_done; - result = sort_boolean(a->post_indexed, b->post_indexed); - if (result != 0) goto gamoc_done; + if (result) + result = g_arch_operand_compare(a->offset, b->offset); - result = sort_boolean(a->write_back, b->write_back); + if (result) + result = g_arch_operand_compare(a->shift, b->shift); - gamoc_done: + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_armv7_maccess_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } return result; @@ -392,11 +501,17 @@ static GArchOperand *g_armv7_maccess_operand_get_inner_operand_from_path(const G static void g_armv7_maccess_operand_print(const GArmV7MAccessOperand *operand, GBufferLine *line) { + bool post; /* Forme post-indexée ? */ + bool wback; /* Ecriture après coup ? */ + + post = g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7MAOF_POST_INDEXED); + wback = g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7MAOF_WRITE_BACK); + g_buffer_line_append_text(line, DLC_ASSEMBLY, "[", 1, RTT_HOOK, NULL); g_arch_operand_print(operand->base, line); - if (operand->post_indexed) + if (post) g_buffer_line_append_text(line, DLC_ASSEMBLY, "]", 1, RTT_HOOK, NULL); if (operand->offset != NULL) @@ -417,10 +532,10 @@ static void g_armv7_maccess_operand_print(const GArmV7MAccessOperand *operand, G } - if (!operand->post_indexed) + if (!post) g_buffer_line_append_text(line, DLC_ASSEMBLY, "]", 1, RTT_HOOK, NULL); - if (operand->post_indexed && operand->write_back) + if (post && wback) g_buffer_line_append_text(line, DLC_ASSEMBLY, "!", 1, RTT_PUNCT, NULL); } @@ -428,306 +543,169 @@ static void g_armv7_maccess_operand_print(const GArmV7MAccessOperand *operand, G /****************************************************************************** * * -* Paramètres : base = représente le registre de la base d'accès. * -* offset = détermine le décalage entre l'adresse et la base. * -* shift = opération de décalage pour jouer sur le décalage. * -* post = précise la forme donnée au décalage à appliquer. * -* wback = indique une mise à jour de la base après usage. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Crée un accès à la mémoire depuis une base et un décalage. * +* Description : Fournit une liste de candidats embarqués par un candidat. * * * -* Retour : Opérande mis en place. * +* Retour : Liste de candidats internes ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_armv7_maccess_operand_new(GArchOperand *base, GArchOperand *offset, GArchOperand *shift, bool post, bool wback) +static GArchOperand **g_armv7_maccess_operand_list_inner_instances(const GArmV7MAccessOperand *operand, size_t *count) { - GArmV7MAccessOperand *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_ARMV7_MACCESS_OPERAND, NULL); - - result->base = base; - result->offset = offset; - result->shift = shift; - - result->post_indexed = post; - result->write_back = wback; - - return G_ARCH_OPERAND(result); - -} + GArchOperand **result; /* Instances à retourner */ + size_t idx; /* Indice de traitement */ + *count = 1; -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Founit la base d'un accès à la mémoire. * -* * -* Retour : Opérande en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchOperand *g_armv7_maccess_operand_get_base(const GArmV7MAccessOperand *operand) -{ - return operand->base; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Founit le décalage d'un accès à la mémoire depuis la base. * -* * -* Retour : Opérande en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchOperand *g_armv7_maccess_operand_get_offset(const GArmV7MAccessOperand *operand) -{ - return operand->offset; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Founit le décalage d'un décalage pour un accès mémoire. * -* * -* Retour : Opérande en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchOperand *g_armv7_maccess_operand_get_shift(const GArmV7MAccessOperand *operand) -{ - return operand->shift; + if (operand->offset != NULL) + (*count)++; -} + if (operand->shift != NULL) + (*count)++; + result = malloc(*count * sizeof(GArchOperand *)); -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Indique si le décalage est post-indexé. * -* * -* Retour : Statut des opérations menées. * -* * -* Remarques : - * -* * -******************************************************************************/ + result[0] = operand->base; + g_object_ref(G_OBJECT(result[0])); -bool g_armv7_maccess_operand_is_post_indexed(const GArmV7MAccessOperand *operand) -{ - return operand->post_indexed; + if (operand->offset != NULL) + { + result[1] = operand->offset; + g_object_ref(G_OBJECT(result[1])); -} + idx = 2; + } + else + idx = 1; -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Indique si la base est mise à jour après usage. * -* * -* Retour : Statut des opérations menées. * -* * -* Remarques : - * -* * -******************************************************************************/ + if (operand->shift != NULL) + { + result[idx] = operand->shift; + g_object_ref(G_OBJECT(result[idx])); + } -bool g_armv7_maccess_operand_has_to_write_back(const GArmV7MAccessOperand *operand) -{ - return operand->write_back; + return result; } - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* instances = liste de candidats internes devenus singletons. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Charge un opérande depuis une mémoire tampon. * +* Description : Met à jour une liste de candidats embarqués par un candidat. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_maccess_operand_unserialize(GArmV7MAccessOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static void g_armv7_maccess_operand_update_inner_instances(GArmV7MAccessOperand *operand, GArchOperand **instances, size_t count) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - GArchOperand *subop; /* Sous-opérande à intégrer */ - uint8_t boolean; /* Valeur booléenne */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_maccess_operand_parent_class); - - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); - - if (result) - { - subop = g_arch_operand_load(storage, format, pbuf); - - if (subop == NULL) - result = false; - - else - operand->base = subop; - - } - - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result && boolean == 1) - { - subop = g_arch_operand_load(storage, format, pbuf); +#ifndef NDEBUG + size_t idx_check; /* Décompte des éléments utiles*/ +#endif + size_t i; /* Boucle de parcours */ - if (subop == NULL) - result = false; +#ifndef NDEBUG + idx_check = 1; - else - operand->offset = subop; + if (operand->offset != NULL) + (idx_check)++; - } + if (operand->shift != NULL) + (idx_check)++; - } + assert(count == idx_check); +#endif - if (result) + for (i = 0; i < count; i++) { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result && boolean == 1) + switch (i) { - subop = g_arch_operand_load(storage, format, pbuf); - - if (subop == NULL) - result = false; - - else - operand->shift = subop; + case 0: + g_clear_object(&operand->base); + operand->base = instances[i]; + break; + + case 1: + if (operand->offset != NULL) + { + g_clear_object(&operand->offset); + operand->offset = instances[i]; + } + else + { + assert(count == 2); + + g_clear_object(&operand->shift); + operand->shift = instances[i]; + + } + break; + + case 2: + g_clear_object(&operand->shift); + operand->shift = instances[i]; + break; } - } - - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result) - operand->post_indexed = (boolean == 1 ? true : false); + g_object_ref(G_OBJECT(instances[i])); } - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - - if (result) - operand->write_back = (boolean == 1 ? true : false); - - } - - return result; - } /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * * * -* Retour : Bilan de l'opération. * +* Retour : Empreinte de l'élément représenté. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_maccess_operand_serialize(const GArmV7MAccessOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static guint g_armv7_maccess_operand_hash(const GArmV7MAccessOperand *operand, bool lock) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t boolean; /* Valeur booléenne */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_maccess_operand_parent_class); - - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); - - if (result) - result = g_arch_operand_store(operand->base, storage, pbuf); - - if (result) - { - if (operand->offset == NULL) - result = extend_packed_buffer(pbuf, (uint8_t []) { 0 }, sizeof(uint8_t), false); - - else - { - result = extend_packed_buffer(pbuf, (uint8_t []) { 1 }, sizeof(uint8_t), false); + guint result; /* Valeur à retourner */ + operand_extra_data_t *extra; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + size_t count; /* Quantité d'éléments utiles */ - if (result) - result = g_arch_operand_store(operand->offset, storage, pbuf); + extra = GET_ARCH_OP_EXTRA(G_ARCH_OPERAND(operand)); - } + if (lock) + LOCK_GOBJECT_EXTRA(extra); - } + class = G_ARCH_OPERAND_CLASS(g_armv7_maccess_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); - if (result) - { - if (operand->shift == NULL) - result = extend_packed_buffer(pbuf, (uint8_t []) { 0 }, sizeof(uint8_t), false); + count = 1; - else - { - result = extend_packed_buffer(pbuf, (uint8_t []) { 1 }, sizeof(uint8_t), false); - - if (result) - result = g_arch_operand_store(operand->shift, storage, pbuf); - - } + if (operand->offset != NULL) + (count)++; - } + if (operand->shift != NULL) + (count)++; - if (result) - { - boolean = (operand->post_indexed ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } + result ^= count; - if (result) - { - boolean = (operand->write_back ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); return result; diff --git a/plugins/arm/v7/operands/maccess.h b/plugins/arm/v7/operands/maccess.h index bc80cfa..eb39c30 100644 --- a/plugins/arm/v7/operands/maccess.h +++ b/plugins/arm/v7/operands/maccess.h @@ -36,6 +36,15 @@ +/* Etats particuliers d'un opérande de valeur immédiate */ +typedef enum _A7MAccessOpFlag +{ + A7MAOF_POST_INDEXED = AOF_USER_FLAG(0), /* Position du décalage */ + A7MAOF_WRITE_BACK = AOF_USER_FLAG(1), /* Mise à jour de la base */ + +} A7MAccessOpFlag; + + #define G_TYPE_ARMV7_MACCESS_OPERAND g_armv7_maccess_operand_get_type() #define G_ARMV7_MACCESS_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARMV7_MACCESS_OPERAND, GArmV7MAccessOperand)) #define G_IS_ARMV7_MACCESS_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARMV7_MACCESS_OPERAND)) diff --git a/plugins/arm/v7/operands/offset.c b/plugins/arm/v7/operands/offset.c index 75fd6a0..724523d 100644 --- a/plugins/arm/v7/operands/offset.c +++ b/plugins/arm/v7/operands/offset.c @@ -24,22 +24,26 @@ #include "offset.h" +#include <assert.h> #include <stdio.h> #include <string.h> -#include <arch/operand-int.h> -#include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> +#include "../operand-int.h" + + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + /* Définition d'un opérande visant à constituer un décalage relatif ARMv7 (instance) */ struct _GArmV7OffsetOperand { - GArchOperand parent; /* Instance parente */ + GArmV7Operand parent; /* Instance parente */ - bool positive; /* Sens du décalage */ GArchOperand *value; /* Valeur du décalage */ }; @@ -48,7 +52,7 @@ struct _GArmV7OffsetOperand /* Définition d'un opérande visant à constituer un décalage relatif ARMv7 (classe) */ struct _GArmV7OffsetOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; @@ -65,8 +69,13 @@ static void g_armv7_offset_operand_dispose(GArmV7OffsetOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_offset_operand_finalize(GArmV7OffsetOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_armv7_offset_operand_compare(const GArmV7OffsetOperand *, const GArmV7OffsetOperand *); +static int g_armv7_offset_operand_compare(const GArmV7OffsetOperand *, const GArmV7OffsetOperand *, bool); /* Détermine le chemin conduisant à un opérande interne. */ static char *g_armv7_offset_operand_find_inner_operand_path(const GArmV7OffsetOperand *, const GArchOperand *); @@ -77,21 +86,21 @@ static GArchOperand *g_armv7_offset_operand_get_inner_operand_from_path(const GA /* Traduit un opérande en version humainement lisible. */ static void g_armv7_offset_operand_print(const GArmV7OffsetOperand *, GBufferLine *); +/* Fournit une liste de candidats embarqués par un candidat. */ +static GArchOperand **g_armv7_offset_operand_list_inner_instances(const GArmV7OffsetOperand *, size_t *); - -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* Met à jour une liste de candidats embarqués par un candidat. */ +static void g_armv7_offset_operand_update_inner_instances(GArmV7OffsetOperand *, GArchOperand **, size_t); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_offset_operand_unserialize(GArmV7OffsetOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); - -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_offset_operand_serialize(const GArmV7OffsetOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un décalage relatif ARMv7. */ -G_DEFINE_TYPE(GArmV7OffsetOperand, g_armv7_offset_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7OffsetOperand, g_armv7_offset_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -124,8 +133,11 @@ static void g_armv7_offset_operand_class_init(GArmV7OffsetOperandClass *klass) operand->print = (operand_print_fc)g_armv7_offset_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_offset_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_offset_operand_serialize; + operand->list_inner = (operand_list_inners_fc)g_armv7_offset_operand_list_inner_instances; + operand->update_inner = (operand_update_inners_fc)g_armv7_offset_operand_update_inner_instances; + + operand->load = g_arch_operand_load_generic_fixed_1; + operand->store = g_arch_operand_store_generic_fixed; } @@ -163,8 +175,7 @@ static void g_armv7_offset_operand_init(GArmV7OffsetOperand *operand) static void g_armv7_offset_operand_dispose(GArmV7OffsetOperand *operand) { - if (operand->value != NULL) - g_object_unref(G_OBJECT(operand->value)); + g_clear_object(&operand->value); G_OBJECT_CLASS(g_armv7_offset_operand_parent_class)->dispose(G_OBJECT(operand)); @@ -192,8 +203,69 @@ static void g_armv7_offset_operand_finalize(GArmV7OffsetOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : positive = indique si la quantité doit être ajoutée ou non. * +* value = valeur du décalage à appliquer. * +* * +* Description : Crée un décalage selon un sens et une valeur donnés. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_offset_operand_new(bool positive, GArchOperand *value) +{ + GArmV7OffsetOperand *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_ARMV7_OFFSET_OPERAND, NULL); + + if (positive) + g_arch_operand_set_flag(G_ARCH_OPERAND(result), A7OOF_POSITIVE); + + result->value = value; + + return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Founit la valeur utilisée pour un décalage. * +* * +* Retour : Opérande en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_offset_operand_get_value(const GArmV7OffsetOperand *operand) +{ + GArchOperand *result; /* Instance à retourner */ + + result = operand->value; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -203,16 +275,18 @@ static void g_armv7_offset_operand_finalize(GArmV7OffsetOperand *operand) * * ******************************************************************************/ -static int g_armv7_offset_operand_compare(const GArmV7OffsetOperand *a, const GArmV7OffsetOperand *b) +static int g_armv7_offset_operand_compare(const GArmV7OffsetOperand *a, const GArmV7OffsetOperand *b, bool lock) { int result; /* Bilan à faire remonter */ - - result = sort_boolean(a->positive, b->positive); - if (result != 0) goto gaooc_done; + GArchOperandClass *class; /* Classe parente normalisée */ result = g_arch_operand_compare(a->value, b->value); - gaooc_done: + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_armv7_offset_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } return result; @@ -299,7 +373,7 @@ static GArchOperand *g_armv7_offset_operand_get_inner_operand_from_path(const GA static void g_armv7_offset_operand_print(const GArmV7OffsetOperand *operand, GBufferLine *line) { - if (!operand->positive) + if (!g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7OOF_POSITIVE)) g_buffer_line_append_text(line, DLC_ASSEMBLY, "-", 1, RTT_KEY_WORD, NULL); g_arch_operand_print(operand->value, line); @@ -309,127 +383,27 @@ static void g_armv7_offset_operand_print(const GArmV7OffsetOperand *operand, GBu /****************************************************************************** * * -* Paramètres : positive = indique si la quantité doit être ajoutée ou non. * -* value = valeur du décalage à appliquer. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Crée un décalage selon un sens et une valeur donnés. * +* Description : Fournit une liste de candidats embarqués par un candidat. * * * -* Retour : Opérande mis en place. * +* Retour : Liste de candidats internes ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_armv7_offset_operand_new(bool positive, GArchOperand *value) +static GArchOperand **g_armv7_offset_operand_list_inner_instances(const GArmV7OffsetOperand *operand, size_t *count) { - GArmV7OffsetOperand *result; /* Structure à retourner */ + GArchOperand **result; /* Instances à retourner */ - result = g_object_new(G_TYPE_ARMV7_OFFSET_OPERAND, NULL); + *count = 1; - result->positive = positive; - result->value = value; + result = malloc(*count * sizeof(GArchOperand *)); - return G_ARCH_OPERAND(result); - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Indique le sens du décalage représenté. * -* * -* Retour : Indication d'ajout ou de retrait. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool g_armv7_offset_operand_is_positive(const GArmV7OffsetOperand *operand) -{ - return operand->positive; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Founit la valeur utilisée pour un décalage. * -* * -* Retour : Opérande en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchOperand *g_armv7_offset_operand_get_value(const GArmV7OffsetOperand *operand) -{ - GArchOperand *result; /* Instance à retourner */ - - result = operand->value; - - g_object_ref(G_OBJECT(result)); - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un opérande depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_armv7_offset_operand_unserialize(GArmV7OffsetOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) -{ - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - GArchOperand *value; /* Valeur à intégrer */ - uint8_t positive; /* Sens du décalage */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_offset_operand_parent_class); - - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); - - if (result) - { - value = g_arch_operand_load(storage, format, pbuf); - - if (value == NULL) - result = false; - - else - operand->value = value; - - } - - if (result) - { - result = extract_packed_buffer(pbuf, &positive, sizeof(uint8_t), false); - - if (result) - operand->positive = (positive == 1 ? true : false); - - } + result[0] = operand->value; + g_object_ref(G_OBJECT(result[0])); return result; @@ -438,37 +412,25 @@ static bool g_armv7_offset_operand_unserialize(GArmV7OffsetOperand *operand, GAs /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* instances = liste de candidats internes devenus singletons. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Met à jour une liste de candidats embarqués par un candidat. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_offset_operand_serialize(const GArmV7OffsetOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static void g_armv7_offset_operand_update_inner_instances(GArmV7OffsetOperand *operand, GArchOperand **instances, size_t count) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t positive; /* Sens du décalage */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_offset_operand_parent_class); + assert(count == 1); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + g_clear_object(&operand->value); - if (result) - { - positive = (operand->positive ? 1 : 0); - result = extend_packed_buffer(pbuf, &positive, sizeof(uint8_t), false); - } - - if (result) - result = g_arch_operand_store(operand->value, storage, pbuf); - - return result; + operand->value = instances[0]; + g_object_ref(G_OBJECT(instances[0])); } diff --git a/plugins/arm/v7/operands/offset.h b/plugins/arm/v7/operands/offset.h index aa4df5e..0b5f1bf 100644 --- a/plugins/arm/v7/operands/offset.h +++ b/plugins/arm/v7/operands/offset.h @@ -36,6 +36,14 @@ +/* Etats particuliers d'un opérande de valeur immédiate */ +typedef enum _A7OffOpFlag +{ + A7OOF_POSITIVE = AOF_USER_FLAG(0), /* Sens du décalage */ + +} A7OffOpFlag; + + #define G_TYPE_ARMV7_OFFSET_OPERAND g_armv7_offset_operand_get_type() #define G_ARMV7_OFFSET_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARMV7_OFFSET_OPERAND, GArmV7OffsetOperand)) #define G_IS_ARMV7_OFFSET_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARMV7_OFFSET_OPERAND)) @@ -57,9 +65,6 @@ GType g_armv7_offset_operand_get_type(void); /* Crée un décalage selon un sens et une valeur donnés. */ GArchOperand *g_armv7_offset_operand_new(bool, GArchOperand *); -/* Indique le sens du décalage représenté. */ -bool g_armv7_offset_operand_is_positive(const GArmV7OffsetOperand *); - /* Founit la valeur utilisée pour un décalage. */ GArchOperand *g_armv7_offset_operand_get_value(const GArmV7OffsetOperand *); diff --git a/plugins/arm/v7/operands/register.c b/plugins/arm/v7/operands/register.c index c9617bd..fa5b887 100644 --- a/plugins/arm/v7/operands/register.c +++ b/plugins/arm/v7/operands/register.c @@ -25,20 +25,29 @@ #include <arch/operands/register-int.h> -#include <gtkext/gtkblockdisplay.h> +#include <common/sort.h> +#include <core/columns.h> +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _a7regop_extra_data_t +{ + operand_extra_data_t parent; /* A laisser en premier */ + + uint8_t alignment; /* Eventuel alignement */ + +} a7regop_extra_data_t; + + /* Définition d'un opérande visant un registre ARMv7 (instance) */ struct _GArmV7RegisterOperand { GRegisterOperand parent; /* Instance parente */ - unsigned int alignment; /* Eventuel alignement */ - bool has_alignment; /* Validité du champ */ - - bool write_back; /* Mise à jour du registre ? */ - }; @@ -50,6 +59,21 @@ struct _GArmV7RegisterOperandClass }; +/** + * Accès aux informations éventuellement déportées. + */ + +#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + +# define GET_ARMV7_REGISTER_OP_EXTRA(op) ((a7regop_extra_data_t *)&((GArchOperand *)op)->extra) + +#else + +# define GET_ARMV7_REGISTER_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), a7regop_extra_data_t) + +#endif + + /* Initialise la classe des opérandes de registre ARMv7. */ static void g_armv7_register_operand_class_init(GArmV7RegisterOperandClass *); @@ -62,20 +86,31 @@ static void g_armv7_register_operand_dispose(GArmV7RegisterOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_register_operand_finalize(GArmV7RegisterOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Compare un opérande avec un autre. */ +static int g_armv7_register_operand_compare(const GArmV7RegisterOperand *, const GArmV7RegisterOperand *, bool); + /* Traduit un opérande en version humainement lisible. */ static void g_armv7_register_operand_print(const GArmV7RegisterOperand *, GBufferLine *); +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_armv7_register_operand_hash(const GArmV7RegisterOperand *, bool); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_armv7_register_operand_load(GArmV7RegisterOperand *, GObjectStorage *, packed_buffer_t *); -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_armv7_register_operand_store(GArmV7RegisterOperand *, GObjectStorage *, packed_buffer_t *); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_register_operand_unserialize(GArmV7RegisterOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); - -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_register_operand_serialize(const GArmV7RegisterOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour un opérande de registre ARMv7. */ @@ -106,10 +141,14 @@ static void g_armv7_register_operand_class_init(GArmV7RegisterOperandClass *klas operand = G_ARCH_OPERAND_CLASS(klass); + operand->compare = (operand_compare_fc)g_armv7_register_operand_compare; + operand->print = (operand_print_fc)g_armv7_register_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_register_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_register_operand_serialize; + operand->hash = (operand_hash_fc)g_armv7_register_operand_hash; + + operand->load = (load_operand_fc)g_armv7_register_operand_load; + operand->store = (store_operand_fc)g_armv7_register_operand_store; } @@ -128,7 +167,6 @@ static void g_armv7_register_operand_class_init(GArmV7RegisterOperandClass *klas static void g_armv7_register_operand_init(GArmV7RegisterOperand *operand) { - operand->write_back = false; } @@ -173,33 +211,6 @@ static void g_armv7_register_operand_finalize(GArmV7RegisterOperand *operand) /****************************************************************************** * * -* Paramètres : operand = opérande à traiter. * -* line = ligne tampon où imprimer l'opérande donné. * -* * -* Description : Traduit un opérande en version humainement lisible. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_armv7_register_operand_print(const GArmV7RegisterOperand *operand, GBufferLine *line) -{ - GArchOperandClass *parent; /* Classe parente */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_register_operand_parent_class); - - parent->print(G_ARCH_OPERAND(operand), line); - - if (operand->write_back) - g_buffer_line_append_text(line, DLC_ASSEMBLY, "!", 1, RTT_PUNCT, NULL); - -} - - -/****************************************************************************** -* * * Paramètres : reg = registre déjà en place. * * * * Description : Crée un opérande visant un registre ARMv7. * @@ -238,9 +249,20 @@ GArchOperand *g_armv7_register_operand_new(GArmV7Register *reg) void g_armv7_register_operand_define_alignement(GArmV7RegisterOperand *operand, unsigned int align) { - operand->alignment = align; + a7regop_extra_data_t *extra; /* Données internes à manipuler*/ + + extra = GET_ARMV7_REGISTER_OP_EXTRA(operand); + + LOCK_GOBJECT_EXTRA(extra); + + extra->alignment = align; - operand->has_alignment = true; + if (align > 0) + _g_arch_operand_set_flag(G_ARCH_OPERAND(operand), A7ROF_HAS_ALIGNMENT, false); + else + _g_arch_operand_unset_flag(G_ARCH_OPERAND(operand), A7ROF_HAS_ALIGNMENT, false); + + UNLOCK_GOBJECT_EXTRA(extra); } @@ -260,83 +282,159 @@ void g_armv7_register_operand_define_alignement(GArmV7RegisterOperand *operand, void g_armv7_register_operand_write_back(GArmV7RegisterOperand *operand, bool wback) { - operand->write_back = wback; + g_arch_operand_set_flag(G_ARCH_OPERAND(operand), A7ROF_WRITE_BACK); } + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : operand = opérande représentant un registre. * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * -* Description : Indique si le registre est mis à jour après coup. * +* Description : Compare un opérande avec un autre. * * * -* Retour : Evolution du registre. * +* Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ -bool g_armv7_register_operand_is_written_back(const GArmV7RegisterOperand *operand) +static int g_armv7_register_operand_compare(const GArmV7RegisterOperand *a, const GArmV7RegisterOperand *b, bool lock) { - bool result; /* Statut à retourner */ + int result; /* Bilan à faire remonter */ + a7regop_extra_data_t *ea; /* Données insérées à consulter*/ + a7regop_extra_data_t *eb; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + + ea = GET_ARMV7_REGISTER_OP_EXTRA(a); + eb = GET_ARMV7_REGISTER_OP_EXTRA(b); - result = operand->write_back; + if (lock) + { + LOCK_GOBJECT_EXTRA(ea); + LOCK_GOBJECT_EXTRA(eb); + } + + result = sort_unsigned_long(ea->alignment, eb->alignment); + + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_armv7_register_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } + + if (lock) + { + UNLOCK_GOBJECT_EXTRA(eb); + UNLOCK_GOBJECT_EXTRA(ea); + } return result; } +/****************************************************************************** +* * +* Paramètres : operand = opérande à traiter. * +* line = ligne tampon où imprimer l'opérande donné. * +* * +* Description : Traduit un opérande en version humainement lisible. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv7_register_operand_print(const GArmV7RegisterOperand *operand, GBufferLine *line) +{ + GArchOperandClass *parent; /* Classe parente */ + + parent = G_ARCH_OPERAND_CLASS(g_armv7_register_operand_parent_class); + + parent->print(G_ARCH_OPERAND(operand), line); -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ + if (g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7ROF_WRITE_BACK)) + g_buffer_line_append_text(line, DLC_ASSEMBLY, "!", 1, RTT_PUNCT, NULL); + +} /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * * * -* Description : Charge un opérande depuis une mémoire tampon. * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * * * -* Retour : Bilan de l'opération. * +* Retour : Empreinte de l'élément représenté. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_register_operand_unserialize(GArmV7RegisterOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static guint g_armv7_register_operand_hash(const GArmV7RegisterOperand *operand, bool lock) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t boolean; /* Valeur booléenne */ + guint result; /* Valeur à retourner */ + a7regop_extra_data_t *extra; /* Données internes à manipuler*/ + GArchOperandClass *class; /* Classe parente normalisée */ - parent = G_ARCH_OPERAND_CLASS(g_armv7_register_operand_parent_class); + extra = GET_ARMV7_REGISTER_OP_EXTRA(operand); - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); + if (lock) + LOCK_GOBJECT_EXTRA(extra); - if (result) - { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); + class = G_ARCH_OPERAND_CLASS(g_armv7_register_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); - if (result) - operand->has_alignment = (boolean == 1 ? true : false); + result ^= extra->alignment; - } + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * +* * +* Description : Charge un contenu depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - if (result && operand->has_alignment) - result = extract_packed_buffer(pbuf, &operand->alignment, sizeof(unsigned int), true); +static bool g_armv7_register_operand_load(GArmV7RegisterOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchOperandClass *parent; /* Classe parente à consulter */ + a7regop_extra_data_t *extra; /* Données internes à manipuler*/ + + parent = G_ARCH_OPERAND_CLASS(g_armv7_register_operand_parent_class); + + result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); - if (result) + if (result && g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7ROF_HAS_ALIGNMENT)) { - result = extract_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); + extra = GET_ARMV7_REGISTER_OP_EXTRA(operand); - if (result) - operand->write_back = (boolean == 1 ? true : false); + result = extract_packed_buffer(pbuf, &extra->alignment, sizeof(uint8_t), false); } @@ -347,11 +445,11 @@ static bool g_armv7_register_operand_unserialize(GArmV7RegisterOperand *operand, /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : operand = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -359,29 +457,22 @@ static bool g_armv7_register_operand_unserialize(GArmV7RegisterOperand *operand, * * ******************************************************************************/ -static bool g_armv7_register_operand_serialize(const GArmV7RegisterOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_armv7_register_operand_store(GArmV7RegisterOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ - uint8_t boolean; /* Valeur booléenne */ + a7regop_extra_data_t *extra; /* Données internes à manipuler*/ parent = G_ARCH_OPERAND_CLASS(g_armv7_register_operand_parent_class); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); - if (result) + if (result && g_arch_operand_has_flag(G_ARCH_OPERAND(operand), A7ROF_HAS_ALIGNMENT)) { - boolean = (operand->has_alignment ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); - } + extra = GET_ARMV7_REGISTER_OP_EXTRA(operand); - if (result && operand->has_alignment) - result = extend_packed_buffer(pbuf, &operand->alignment, sizeof(unsigned int), true); + result = extend_packed_buffer(pbuf, &extra->alignment, sizeof(uint8_t), false); - if (result) - { - boolean = (operand->write_back ? 1 : 0); - result = extend_packed_buffer(pbuf, &boolean, sizeof(uint8_t), false); } return result; diff --git a/plugins/arm/v7/operands/register.h b/plugins/arm/v7/operands/register.h index 241c101..26e03c0 100644 --- a/plugins/arm/v7/operands/register.h +++ b/plugins/arm/v7/operands/register.h @@ -36,6 +36,15 @@ +/* Etats particuliers d'un opérande de valeur immédiate */ +typedef enum _A7RegOpFlag +{ + A7ROF_HAS_ALIGNMENT = AOF_USER_FLAG(0), /* Validité de l'alignement */ + A7ROF_WRITE_BACK = AOF_USER_FLAG(1), /* Mise à jour du registre ? */ + +} A7RegOpFlag; + + #define G_TYPE_ARMV7_REGISTER_OPERAND g_armv7_register_operand_get_type() #define G_ARMV7_REGISTER_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_ARMV7_REGISTER_OPERAND, GArmV7RegisterOperand)) #define G_IS_ARMV7_REGISTER_OPERAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_ARMV7_REGISTER_OPERAND)) @@ -63,9 +72,6 @@ void g_armv7_register_operand_define_alignement(GArmV7RegisterOperand *, unsigne /* Détermine si le registre est mis à jour après l'opération. */ void g_armv7_register_operand_write_back(GArmV7RegisterOperand *, bool); -/* Indique si le registre est mis à jour après coup. */ -bool g_armv7_register_operand_is_written_back(const GArmV7RegisterOperand *); - #endif /* _PLUGINS_ARM_V7_OPERANDS_REGISTER_H */ diff --git a/plugins/arm/v7/operands/reglist.c b/plugins/arm/v7/operands/reglist.c index 99fc269..b525f28 100644 --- a/plugins/arm/v7/operands/reglist.c +++ b/plugins/arm/v7/operands/reglist.c @@ -28,21 +28,24 @@ #include <malloc.h> -#include <arch/operand-int.h> #include <arch/register.h> #include <arch/storage.h> #include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> +#include "../operand-int.h" #include "../registers/basic.h" +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + /* Définition d'un opérande listant une série de registres ARM (instance) */ struct _GArmV7RegListOperand { - GArchOperand parent; /* Instance parente */ + GArmV7Operand parent; /* Instance parente */ GArmV7Register **registers; /* Liste de registres intégrés */ size_t count; /* Taille de cette liste */ @@ -53,7 +56,7 @@ struct _GArmV7RegListOperand /* Définition d'un opérande listant une série de registres ARM (classe) */ struct _GArmV7RegListOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; @@ -70,27 +73,35 @@ static void g_armv7_reglist_operand_dispose(GArmV7RegListOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_reglist_operand_finalize(GArmV7RegListOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_armv7_reglist_operand_compare(const GArmV7RegListOperand *, const GArmV7RegListOperand *); +static int g_armv7_reglist_operand_compare(const GArmV7RegListOperand *, const GArmV7RegListOperand *, bool); /* Traduit un opérande en version humainement lisible. */ static void g_armv7_reglist_operand_print(const GArmV7RegListOperand *, GBufferLine *); +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_armv7_reglist_operand_hash(const GArmV7RegListOperand *, bool); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_armv7_reglist_operand_load(GArmV7RegListOperand *, GObjectStorage *, packed_buffer_t *); -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ - +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_armv7_reglist_operand_store(GArmV7RegListOperand *, GObjectStorage *, packed_buffer_t *); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_reglist_operand_unserialize(GArmV7RegListOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_reglist_operand_serialize(const GArmV7RegListOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour une liste de registres ARM. */ -G_DEFINE_TYPE(GArmV7RegListOperand, g_armv7_reglist_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7RegListOperand, g_armv7_reglist_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -119,8 +130,10 @@ static void g_armv7_reglist_operand_class_init(GArmV7RegListOperandClass *klass) operand->compare = (operand_compare_fc)g_armv7_reglist_operand_compare; operand->print = (operand_print_fc)g_armv7_reglist_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_reglist_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_reglist_operand_serialize; + operand->hash = (operand_hash_fc)g_armv7_reglist_operand_hash; + + operand->load = (load_operand_fc)g_armv7_reglist_operand_load; + operand->store = (store_operand_fc)g_armv7_reglist_operand_store; } @@ -162,7 +175,7 @@ static void g_armv7_reglist_operand_dispose(GArmV7RegListOperand *operand) size_t i; /* Boucle de parcours */ for (i = 0; i < operand->count; i++) - g_object_unref(G_OBJECT(operand->registers[i])); + g_clear_object(&operand->registers[i]); G_OBJECT_CLASS(g_armv7_reglist_operand_parent_class)->dispose(G_OBJECT(operand)); @@ -193,88 +206,6 @@ static void g_armv7_reglist_operand_finalize(GArmV7RegListOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * -* * -* Description : Compare un opérande avec un autre. * -* * -* Retour : Bilan de la comparaison. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int g_armv7_reglist_operand_compare(const GArmV7RegListOperand *a, const GArmV7RegListOperand *b) -{ - int result; /* Bilan à faire remonter */ - size_t i; /* Boucle de parcours */ - GArchRegister *ra; /* Registre de la liste A */ - GArchRegister *rb; /* Registre de la liste B */ - - /* Création de l'objet... */ - if (b == NULL) - { - result = 1; - goto garoc_done; - } - - result = sort_unsigned_long(a->count, b->count); - if (result != 0) goto garoc_done; - - for (i = 0; i < a->count && result == 0; i++) - { - ra = G_ARCH_REGISTER(a->registers[i]); - rb = G_ARCH_REGISTER(b->registers[i]); - - result = g_arch_register_compare(ra, rb); - - } - - garoc_done: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à traiter. * -* line = ligne tampon où imprimer l'opérande donné. * -* * -* Description : Traduit un opérande en version humainement lisible. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_armv7_reglist_operand_print(const GArmV7RegListOperand *operand, GBufferLine *line) -{ - size_t i; /* Boucle de parcours */ - - g_buffer_line_append_text(line, DLC_ASSEMBLY, "{", 1, RTT_HOOK, NULL); - - for (i = 0; i < operand->count; i++) - { - if (i > 0) - { - g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); - g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); - } - - g_arch_register_print(G_ARCH_REGISTER(operand->registers[i]), line); - - } - - g_buffer_line_append_text(line, DLC_ASSEMBLY, "}", 1, RTT_HOOK, NULL); - -} - - -/****************************************************************************** -* * * Paramètres : selected = masque de bits pour les registres à intégrer. * * * * Description : Crée une liste vierge de registres ARM. * @@ -322,8 +253,7 @@ GArchOperand *g_armv7_reglist_operand_new(uint16_t selected) void g_armv7_reglist_add_register(GArmV7RegListOperand *operand, GArmV7Register *reg) { - operand->registers = (GArmV7Register **)realloc(operand->registers, - ++operand->count * sizeof(GArmV7Register *)); + operand->registers = realloc(operand->registers, ++operand->count * sizeof(GArmV7Register *)); operand->registers[operand->count - 1] = reg; @@ -408,68 +338,135 @@ bool g_armv7_reglist_operand_has_register(const GArmV7RegListOperand *operand, c /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * -* Description : Charge un opérande depuis une mémoire tampon. * +* Description : Compare un opérande avec un autre. * * * -* Retour : Bilan de l'opération. * +* Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_reglist_operand_unserialize(GArmV7RegListOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static int g_armv7_reglist_operand_compare(const GArmV7RegListOperand *a, const GArmV7RegListOperand *b, bool lock) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - size_t count; /* Quantité de registres */ - packed_buffer reg_pbuf; /* Tampon des données à écrire */ + int result; /* Bilan à faire remonter */ size_t i; /* Boucle de parcours */ - off64_t pos; /* Position dans le flux */ - GArchRegister *reg; /* Registre restauré */ + GArchRegister *ra; /* Registre de la liste A */ + GArchRegister *rb; /* Registre de la liste B */ + GArchOperandClass *class; /* Classe parente normalisée */ - parent = G_ARCH_OPERAND_CLASS(g_armv7_reglist_operand_parent_class); + /* Création de l'objet... */ + if (b == NULL) + { + result = 1; + goto done; + } - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); + result = sort_unsigned_long(a->count, b->count); - if (result) - result = extract_packed_buffer(pbuf, &count, sizeof(size_t), true); + for (i = 0; i < a->count && result == 0; i++) + { + ra = G_ARCH_REGISTER(a->registers[i]); + rb = G_ARCH_REGISTER(b->registers[i]); - if (result) + result = g_arch_register_compare(ra, rb); + + } + + if (result == 0) { - init_packed_buffer(®_pbuf); + class = G_ARCH_OPERAND_CLASS(g_armv7_reglist_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } - for (i = 0; i < count && result; i++) - { - result = extract_packed_buffer(pbuf, &pos, sizeof(off64_t), true); + done: - if (result) - result = g_asm_storage_load_register_data(storage, ®_pbuf, pos); + return result; - if (result) - { - reg = g_arch_register_load(storage, ®_pbuf); - result = (reg != NULL); - } +} - if (result) - g_armv7_reglist_add_register(operand, G_ARMV7_REGISTER(reg)); +/****************************************************************************** +* * +* Paramètres : operand = opérande à traiter. * +* line = ligne tampon où imprimer l'opérande donné. * +* * +* Description : Traduit un opérande en version humainement lisible. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_armv7_reglist_operand_print(const GArmV7RegListOperand *operand, GBufferLine *line) +{ + size_t i; /* Boucle de parcours */ + + g_buffer_line_append_text(line, DLC_ASSEMBLY, "{", 1, RTT_HOOK, NULL); + + for (i = 0; i < operand->count; i++) + { + if (i > 0) + { + g_buffer_line_append_text(line, DLC_ASSEMBLY, ",", 1, RTT_PUNCT, NULL); + g_buffer_line_append_text(line, DLC_ASSEMBLY, " ", 1, RTT_RAW, NULL); } - exit_packed_buffer(®_pbuf); + g_arch_register_print(G_ARCH_REGISTER(operand->registers[i]), line); } + g_buffer_line_append_text(line, DLC_ASSEMBLY, "}", 1, RTT_HOOK, NULL); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * +* * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * +* * +* Retour : Empreinte de l'élément représenté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static guint g_armv7_reglist_operand_hash(const GArmV7RegListOperand *operand, bool lock) +{ + guint result; /* Valeur à retourner */ + operand_extra_data_t *extra; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + size_t i; /* Boucle de parcours */ + + extra = GET_ARCH_OP_EXTRA(G_ARCH_OPERAND(operand)); + + if (lock) + LOCK_GOBJECT_EXTRA(extra); + + class = G_ARCH_OPERAND_CLASS(g_armv7_reglist_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); + + result ^= operand->count; + + for (i = 0; i < operand->count; i++) + result ^= g_arch_register_hash(G_ARCH_REGISTER(operand->registers[i])); + + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); + return result; } @@ -477,11 +474,11 @@ static bool g_armv7_reglist_operand_unserialize(GArmV7RegListOperand *operand, G /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Charge un contenu depuis une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -489,39 +486,69 @@ static bool g_armv7_reglist_operand_unserialize(GArmV7RegListOperand *operand, G * * ******************************************************************************/ -static bool g_armv7_reglist_operand_serialize(const GArmV7RegListOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_armv7_reglist_operand_load(GArmV7RegListOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ + size_t count; /* Quantité de registres */ size_t i; /* Boucle de parcours */ - off64_t pos; /* Position dans le flux */ - packed_buffer reg_pbuf; /* Tampon des données à écrire */ + GSerializableObject *reg; /* Registre de la liste */ parent = G_ARCH_OPERAND_CLASS(g_armv7_reglist_operand_parent_class); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); if (result) - result = extend_packed_buffer(pbuf, &operand->count, sizeof(size_t), true); + result = extract_packed_buffer(pbuf, &count, sizeof(size_t), true); - if (result) + for (i = 0; i < count && result; i++) { - init_packed_buffer(®_pbuf); + reg = g_object_storage_unpack_object(storage, "registers", pbuf); - for (i = 0; i < operand->count && result; i++) - { - result = g_arch_register_store(G_ARCH_REGISTER(operand->registers[i]), storage, ®_pbuf); + result = (reg != NULL); - if (result) - result = g_asm_storage_store_register_data(storage, ®_pbuf, &pos); + if (result) + g_armv7_reglist_add_register(operand, G_ARMV7_REGISTER(reg)); - if (result) - result = extend_packed_buffer(pbuf, &pos, sizeof(off64_t), true); + } - } + return result; - exit_packed_buffer(®_pbuf); +} + + +/****************************************************************************** +* * +* Paramètres : operand = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à remplir. * +* * +* Description : Sauvegarde un contenu dans une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ +static bool g_armv7_reglist_operand_store(GArmV7RegListOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchOperandClass *parent; /* Classe parente à consulter */ + size_t i; /* Boucle de parcours */ + GSerializableObject *reg; /* Registre de la liste */ + + parent = G_ARCH_OPERAND_CLASS(g_armv7_reglist_operand_parent_class); + + result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); + + if (result) + result = extend_packed_buffer(pbuf, &operand->count, sizeof(size_t), true); + + for (i = 0; i < operand->count && result; i++) + { + reg = G_SERIALIZABLE_OBJECT(operand->registers[i]); + result = g_object_storage_pack_object(storage, "registers", reg, pbuf); } return result; diff --git a/plugins/arm/v7/operands/rotation.c b/plugins/arm/v7/operands/rotation.c index bd99e63..418e5a4 100644 --- a/plugins/arm/v7/operands/rotation.c +++ b/plugins/arm/v7/operands/rotation.c @@ -24,20 +24,26 @@ #include "rotation.h" +#include <assert.h> #include <stdio.h> #include <string.h> -#include <arch/operand-int.h> +#include <core/columns.h> #include <core/logs.h> -#include <gtkext/gtkblockdisplay.h> +#include "../operand-int.h" + + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + /* Définition d'un opérande visant une opérande de rotation ARMv7 (instance) */ struct _GArmV7RotationOperand { - GArchOperand parent; /* Instance parente */ + GArmV7Operand parent; /* Instance parente */ GArchOperand *value; /* Valeur du décalage */ @@ -47,7 +53,7 @@ struct _GArmV7RotationOperand /* Définition d'un opérande visant une opérande de rotation ARMv7 (classe) */ struct _GArmV7RotationOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; @@ -64,8 +70,13 @@ static void g_armv7_rotation_operand_dispose(GArmV7RotationOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_rotation_operand_finalize(GArmV7RotationOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_armv7_rotation_operand_compare(const GArmV7RotationOperand *, const GArmV7RotationOperand *); +static int g_armv7_rotation_operand_compare(const GArmV7RotationOperand *, const GArmV7RotationOperand *, bool); /* Détermine le chemin conduisant à un opérande interne. */ static char *g_armv7_rotation_operand_find_inner_operand_path(const GArmV7RotationOperand *, const GArchOperand *); @@ -76,21 +87,21 @@ static GArchOperand *g_armv7_rotation_operand_get_inner_operand_from_path(const /* Traduit un opérande en version humainement lisible. */ static void g_armv7_rotation_operand_print(const GArmV7RotationOperand *, GBufferLine *); +/* Fournit une liste de candidats embarqués par un candidat. */ +static GArchOperand **g_armv7_rotation_operand_list_inner_instances(const GArmV7RotationOperand *, size_t *); - -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* Met à jour une liste de candidats embarqués par un candidat. */ +static void g_armv7_rotation_operand_update_inner_instances(GArmV7RotationOperand *, GArchOperand **, size_t); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_rotation_operand_unserialize(GArmV7RotationOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); - -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_rotation_operand_serialize(const GArmV7RotationOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour une opérande de rotation ARMv7. */ -G_DEFINE_TYPE(GArmV7RotationOperand, g_armv7_rotation_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7RotationOperand, g_armv7_rotation_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -123,8 +134,11 @@ static void g_armv7_rotation_operand_class_init(GArmV7RotationOperandClass *klas operand->print = (operand_print_fc)g_armv7_rotation_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_rotation_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_rotation_operand_serialize; + operand->list_inner = (operand_list_inners_fc)g_armv7_rotation_operand_list_inner_instances; + operand->update_inner = (operand_update_inners_fc)g_armv7_rotation_operand_update_inner_instances; + + operand->load = g_arch_operand_load_generic_fixed_1; + operand->store = g_arch_operand_store_generic_fixed; } @@ -162,8 +176,7 @@ static void g_armv7_rotation_operand_init(GArmV7RotationOperand *operand) static void g_armv7_rotation_operand_dispose(GArmV7RotationOperand *operand) { - if (operand->value != NULL) - g_object_unref(G_OBJECT(operand->value)); + g_clear_object(&operand->value); G_OBJECT_CLASS(g_armv7_rotation_operand_parent_class)->dispose(G_OBJECT(operand)); @@ -191,8 +204,65 @@ static void g_armv7_rotation_operand_finalize(GArmV7RotationOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : - * +* * +* Description : Crée un réceptacle pour opérandes de rotation ARMv7. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_rotation_operand_new(GArchOperand *value) +{ + GArmV7RotationOperand *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_ARMV7_ROTATION_OPERAND, NULL); + + result->value = value; + + return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Founit la valeur utilisée pour une rotation. * +* * +* Retour : Opérande en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_rotation_operand_get_value(const GArmV7RotationOperand *operand) +{ + GArchOperand *result; /* Instance à retourner */ + + result = operand->value; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -202,12 +272,19 @@ static void g_armv7_rotation_operand_finalize(GArmV7RotationOperand *operand) * * ******************************************************************************/ -static int g_armv7_rotation_operand_compare(const GArmV7RotationOperand *a, const GArmV7RotationOperand *b) +static int g_armv7_rotation_operand_compare(const GArmV7RotationOperand *a, const GArmV7RotationOperand *b, bool lock) { int result; /* Bilan à faire remonter */ + GArchOperandClass *class; /* Classe parente normalisée */ result = g_arch_operand_compare(a->value, b->value); + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_armv7_rotation_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } + return result; } @@ -326,96 +403,27 @@ static void g_armv7_rotation_operand_print(const GArmV7RotationOperand *operand, /****************************************************************************** * * -* Paramètres : - * -* * -* Description : Crée un réceptacle pour opérandes de rotation ARMv7. * -* * -* Retour : Opérande mis en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchOperand *g_armv7_rotation_operand_new(GArchOperand *value) -{ - GArmV7RotationOperand *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_ARMV7_ROTATION_OPERAND, NULL); - - result->value = value; - - return G_ARCH_OPERAND(result); - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Founit la valeur utilisée pour une rotation. * -* * -* Retour : Opérande en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GArchOperand *g_armv7_rotation_operand_get_value(const GArmV7RotationOperand *operand) -{ - GArchOperand *result; /* Instance à retourner */ - - result = operand->value; - - g_object_ref(G_OBJECT(result)); - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Charge un opérande depuis une mémoire tampon. * +* Description : Fournit une liste de candidats embarqués par un candidat. * * * -* Retour : Bilan de l'opération. * +* Retour : Liste de candidats internes ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_rotation_operand_unserialize(GArmV7RotationOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static GArchOperand **g_armv7_rotation_operand_list_inner_instances(const GArmV7RotationOperand *operand, size_t *count) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - GArchOperand *value; /* Valeur à intégrer */ + GArchOperand **result; /* Instances à retourner */ - parent = G_ARCH_OPERAND_CLASS(g_armv7_rotation_operand_parent_class); + *count = 1; - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); - - if (result) - { - value = g_arch_operand_load(storage, format, pbuf); + result = malloc(*count * sizeof(GArchOperand *)); - if (value == NULL) - result = false; - - else - operand->value = value; - - } + result[0] = operand->value; + g_object_ref(G_OBJECT(result[0])); return result; @@ -424,30 +432,25 @@ static bool g_armv7_rotation_operand_unserialize(GArmV7RotationOperand *operand, /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* instances = liste de candidats internes devenus singletons. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Met à jour une liste de candidats embarqués par un candidat. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static bool g_armv7_rotation_operand_serialize(const GArmV7RotationOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static void g_armv7_rotation_operand_update_inner_instances(GArmV7RotationOperand *operand, GArchOperand **instances, size_t count) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - - parent = G_ARCH_OPERAND_CLASS(g_armv7_rotation_operand_parent_class); + assert(count == 1); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + g_clear_object(&operand->value); - if (result) - result = g_arch_operand_store(operand->value, storage, pbuf); - - return result; + operand->value = instances[0]; + g_object_ref(G_OBJECT(instances[0])); } diff --git a/plugins/arm/v7/operands/shift.c b/plugins/arm/v7/operands/shift.c index a25f36c..ee18cf0 100644 --- a/plugins/arm/v7/operands/shift.c +++ b/plugins/arm/v7/operands/shift.c @@ -24,22 +24,37 @@ #include "shift.h" +#include <assert.h> #include <stdio.h> #include <string.h> -#include <arch/operand-int.h> #include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> +#include "../operand-int.h" + + + +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _a7shiftop_extra_data_t +{ + operand_extra_data_t parent; /* A laisser en premier */ + + SRType shift_type; /* Type de décalage */ + +} a7shiftop_extra_data_t; + /* Définition d'un opérande visant une opérande de décalage ARMv7 (instance) */ struct _GArmV7ShiftOperand { - GArchOperand parent; /* Instance parente */ + GArmV7Operand parent; /* Instance parente */ - SRType shift_type; /* Type de décalage */ GArchOperand *shift_value; /* Valeur du décalage */ }; @@ -48,11 +63,26 @@ struct _GArmV7ShiftOperand /* Définition d'un opérande visant une opérande de décalage ARMv7 (classe) */ struct _GArmV7ShiftOperandClass { - GArchOperandClass parent; /* Classe parente */ + GArmV7OperandClass parent; /* Classe parente */ }; +/** + * Accès aux informations éventuellement déportées. + */ + +#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + +# define GET_ARMV7_SHIFT_OP_EXTRA(op) ((a7shiftop_extra_data_t *)&((GArchOperand *)op)->extra) + +#else + +# define GET_ARMV7_SHIFT_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), a7shiftop_extra_data_t) + +#endif + + /* Initialise la classe des opérandes de décalage ARMv7. */ static void g_armv7_shift_operand_class_init(GArmV7ShiftOperandClass *); @@ -65,8 +95,13 @@ static void g_armv7_shift_operand_dispose(GArmV7ShiftOperand *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_shift_operand_finalize(GArmV7ShiftOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_armv7_shift_operand_compare(const GArmV7ShiftOperand *, const GArmV7ShiftOperand *); +static int g_armv7_shift_operand_compare(const GArmV7ShiftOperand *, const GArmV7ShiftOperand *, bool); /* Détermine le chemin conduisant à un opérande interne. */ static char *g_armv7_shift_operand_find_inner_operand_path(const GArmV7ShiftOperand *, const GArchOperand *); @@ -77,21 +112,30 @@ static GArchOperand *g_armv7_shift_operand_get_inner_operand_from_path(const GAr /* Traduit un opérande en version humainement lisible. */ static void g_armv7_shift_operand_print(const GArmV7ShiftOperand *, GBufferLine *); +/* Fournit une liste de candidats embarqués par un candidat. */ +static GArchOperand **g_armv7_shift_operand_list_inner_instances(const GArmV7ShiftOperand *, size_t *); +/* Met à jour une liste de candidats embarqués par un candidat. */ +static void g_armv7_shift_operand_update_inner_instances(GArmV7ShiftOperand *, GArchOperand **, size_t); -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_armv7_shift_operand_hash(const GArmV7ShiftOperand *, bool); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_armv7_shift_operand_load(GArmV7ShiftOperand *, GObjectStorage *, packed_buffer_t *); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_armv7_shift_operand_unserialize(GArmV7ShiftOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_armv7_shift_operand_store(GArmV7ShiftOperand *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_armv7_shift_operand_serialize(const GArmV7ShiftOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ + /* Indique le type défini par la GLib pour une opérande de décalage ARMv7. */ -G_DEFINE_TYPE(GArmV7ShiftOperand, g_armv7_shift_operand, G_TYPE_ARCH_OPERAND); +G_DEFINE_TYPE(GArmV7ShiftOperand, g_armv7_shift_operand, G_TYPE_ARMV7_OPERAND); /****************************************************************************** @@ -124,8 +168,12 @@ static void g_armv7_shift_operand_class_init(GArmV7ShiftOperandClass *klass) operand->print = (operand_print_fc)g_armv7_shift_operand_print; - operand->unserialize = (unserialize_operand_fc)g_armv7_shift_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_armv7_shift_operand_serialize; + operand->list_inner = (operand_list_inners_fc)g_armv7_shift_operand_list_inner_instances; + operand->update_inner = (operand_update_inners_fc)g_armv7_shift_operand_update_inner_instances; + operand->hash = (operand_hash_fc)g_armv7_shift_operand_hash; + + operand->load = (load_operand_fc)g_armv7_shift_operand_load; + operand->store = (store_operand_fc)g_armv7_shift_operand_store; } @@ -163,8 +211,7 @@ static void g_armv7_shift_operand_init(GArmV7ShiftOperand *operand) static void g_armv7_shift_operand_dispose(GArmV7ShiftOperand *operand) { - if (operand->shift_value != NULL) - g_object_unref(G_OBJECT(operand->shift_value)); + g_clear_object(&operand->shift_value); G_OBJECT_CLASS(g_armv7_shift_operand_parent_class)->dispose(G_OBJECT(operand)); @@ -192,8 +239,100 @@ static void g_armv7_shift_operand_finalize(GArmV7ShiftOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : - * +* * +* Description : Crée un réceptacle pour opérande de décalage ARMv7. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_shift_operand_new(SRType type, GArchOperand *value) +{ + GArmV7ShiftOperand *result; /* Structure à retourner */ + a7shiftop_extra_data_t *extra; /* Données insérées à modifier */ + + result = g_object_new(G_TYPE_ARMV7_SHIFT_OPERAND, NULL); + + extra = GET_ARMV7_SHIFT_OP_EXTRA(result); + + extra->shift_type = type; + + result->shift_value = value; + + return G_ARCH_OPERAND(result); + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Indique la forme de décalage représenté. * +* * +* Retour : Type de décalage. * +* * +* Remarques : - * +* * +******************************************************************************/ + +SRType g_armv7_shift_operand_get_shift_type(const GArmV7ShiftOperand *operand) +{ + SRType result; /* Type à retourner */ + a7shiftop_extra_data_t *extra; /* Données insérées à consulter*/ + + extra = GET_ARMV7_SHIFT_OP_EXTRA(operand); + + LOCK_GOBJECT_EXTRA(extra); + + result = extra->shift_type; + + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Founit la valeur utilisée pour un décalage. * +* * +* Retour : Opérande en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_armv7_shift_operand_get_shift_value(const GArmV7ShiftOperand *operand) +{ + GArchOperand *result; /* Instance à retourner */ + + result = operand->shift_value; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -203,16 +342,38 @@ static void g_armv7_shift_operand_finalize(GArmV7ShiftOperand *operand) * * ******************************************************************************/ -static int g_armv7_shift_operand_compare(const GArmV7ShiftOperand *a, const GArmV7ShiftOperand *b) +static int g_armv7_shift_operand_compare(const GArmV7ShiftOperand *a, const GArmV7ShiftOperand *b, bool lock) { int result; /* Bilan à faire remonter */ + a7shiftop_extra_data_t *ea; /* Données insérées à consulter*/ + a7shiftop_extra_data_t *eb; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + + ea = GET_ARMV7_SHIFT_OP_EXTRA(a); + eb = GET_ARMV7_SHIFT_OP_EXTRA(b); + + if (lock) + { + LOCK_GOBJECT_EXTRA(ea); + LOCK_GOBJECT_EXTRA(eb); + } + + result = sort_unsigned_long(ea->shift_type, eb->shift_type); - result = sort_unsigned_long(a->shift_type, b->shift_type); - if (result != 0) goto gasoc_done; + if (result == 0) + result = g_arch_operand_compare(a->shift_value, b->shift_value); - result = g_arch_operand_compare(a->shift_value, b->shift_value); + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_armv7_shift_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } - gasoc_done: + if (lock) + { + UNLOCK_GOBJECT_EXTRA(eb); + UNLOCK_GOBJECT_EXTRA(ea); + } return result; @@ -299,7 +460,11 @@ static GArchOperand *g_armv7_shift_operand_get_inner_operand_from_path(const GAr static void g_armv7_shift_operand_print(const GArmV7ShiftOperand *operand, GBufferLine *line) { - switch (operand->shift_type) + SRType shift_type; /* Type porté par l'opérande */ + + shift_type = g_armv7_shift_operand_get_shift_type(operand); + + switch (shift_type) { case SRType_LSL: g_buffer_line_append_text(line, DLC_ASSEMBLY, "lsl", 3, RTT_KEY_WORD, NULL); @@ -327,88 +492,106 @@ static void g_armv7_shift_operand_print(const GArmV7ShiftOperand *operand, GBuff /****************************************************************************** * * -* Paramètres : - * +* Paramètres : operand = objet dont l'instance se veut unique. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Crée un réceptacle pour opérande de décalage ARMv7. * +* Description : Fournit une liste de candidats embarqués par un candidat. * * * -* Retour : Opérande mis en place. * +* Retour : Liste de candidats internes ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_armv7_shift_operand_new(SRType type, GArchOperand *value) +static GArchOperand **g_armv7_shift_operand_list_inner_instances(const GArmV7ShiftOperand *operand, size_t *count) { - GArmV7ShiftOperand *result; /* Structure à retourner */ + GArchOperand **result; /* Instances à retourner */ - result = g_object_new(G_TYPE_ARMV7_SHIFT_OPERAND, NULL); + *count = 1; - result->shift_type = type; - result->shift_value = value; + result = malloc(*count * sizeof(GArchOperand *)); - return G_ARCH_OPERAND(result); + result[0] = operand->shift_value; + g_object_ref(G_OBJECT(result[0])); + + return result; } /****************************************************************************** * * -* Paramètres : operand = opérande à consulter. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* instances = liste de candidats internes devenus singletons. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Indique la forme de décalage représenté. * +* Description : Met à jour une liste de candidats embarqués par un candidat. * * * -* Retour : Type de décalage. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -SRType g_armv7_shift_operand_get_shift_type(const GArmV7ShiftOperand *operand) +static void g_armv7_shift_operand_update_inner_instances(GArmV7ShiftOperand *operand, GArchOperand **instances, size_t count) { - return operand->shift_type; + assert(count == 1); + + g_clear_object(&operand->shift_value); + + operand->shift_value = instances[0]; + g_object_ref(G_OBJECT(instances[0])); } /****************************************************************************** * * -* Paramètres : operand = opérande à consulter. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * * * -* Description : Founit la valeur utilisée pour un décalage. * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * * * -* Retour : Opérande en place. * +* Retour : Empreinte de l'élément représenté. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_armv7_shift_operand_get_shift_value(const GArmV7ShiftOperand *operand) +static guint g_armv7_shift_operand_hash(const GArmV7ShiftOperand *operand, bool lock) { - GArchOperand *result; /* Instance à retourner */ + guint result; /* Valeur à retourner */ + a7shiftop_extra_data_t *extra; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + a7shiftop_extra_data_t *op_extra; /* Données internes à manipuler*/ - result = operand->shift_value; + extra = GET_ARMV7_SHIFT_OP_EXTRA(G_ARMV7_SHIFT_OPERAND(operand)); - g_object_ref(G_OBJECT(result)); + if (lock) + LOCK_GOBJECT_EXTRA(extra); - return result; + class = G_ARCH_OPERAND_CLASS(g_armv7_shift_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); -} + op_extra = GET_ARMV7_SHIFT_OP_EXTRA(operand); + result ^= op_extra->shift_type; + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ + return result; + +} /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * * * -* Description : Charge un opérande depuis une mémoire tampon. * +* Description : Charge un contenu depuis une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -416,31 +599,31 @@ GArchOperand *g_armv7_shift_operand_get_shift_value(const GArmV7ShiftOperand *op * * ******************************************************************************/ -static bool g_armv7_shift_operand_unserialize(GArmV7ShiftOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) +static bool g_armv7_shift_operand_load(GArmV7ShiftOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ - GArchOperand *value; /* Valeur à intégrer */ + a7shiftop_extra_data_t *extra; /* Données insérées à modifier */ + uleb128_t value; /* Valeur ULEB128 à charger */ parent = G_ARCH_OPERAND_CLASS(g_armv7_shift_operand_parent_class); - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); - - if (result) - result = extract_packed_buffer(pbuf, &operand->shift_type, sizeof(SRType), true); + result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); if (result) { - value = g_arch_operand_load(storage, format, pbuf); + extra = GET_ARMV7_SHIFT_OP_EXTRA(operand); - if (value == NULL) - result = false; + result = unpack_uleb128(&value, pbuf); - else - operand->shift_value = value; + if (result) + extra->shift_type = value; } + if (result) + result = _g_arch_operand_load_inner_instances(G_ARCH_OPERAND(operand), storage, pbuf, 1); + return result; } @@ -448,11 +631,11 @@ static bool g_armv7_shift_operand_unserialize(GArmV7ShiftOperand *operand, GAsmS /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : operand = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -460,20 +643,26 @@ static bool g_armv7_shift_operand_unserialize(GArmV7ShiftOperand *operand, GAsmS * * ******************************************************************************/ -static bool g_armv7_shift_operand_serialize(const GArmV7ShiftOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_armv7_shift_operand_store(GArmV7ShiftOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ + a7shiftop_extra_data_t *extra; /* Données insérées à modifier */ parent = G_ARCH_OPERAND_CLASS(g_armv7_shift_operand_parent_class); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); if (result) - result = extend_packed_buffer(pbuf, &operand->shift_type, sizeof(SRType), true); + { + extra = GET_ARMV7_SHIFT_OP_EXTRA(operand); + + result = pack_uleb128((uleb128_t []){ extra->shift_type }, pbuf); + + } if (result) - result = g_arch_operand_store(operand->shift_value, storage, pbuf); + result = _g_arch_operand_store_inner_instances(G_ARCH_OPERAND(operand), storage, pbuf, true); return result; diff --git a/plugins/arm/v7/registers/Makefile.am b/plugins/arm/v7/registers/Makefile.am index 94edf09..5f731f9 100644 --- a/plugins/arm/v7/registers/Makefile.am +++ b/plugins/arm/v7/registers/Makefile.am @@ -1,21 +1,16 @@ noinst_LTLIBRARIES = libarmv7registers.la -libarmv7registers_la_SOURCES = \ - banked.h banked.c \ - basic.h basic.c \ - coproc.h coproc.c \ - simd.h simd.c \ +libarmv7registers_la_SOURCES = \ + banked.h banked.c \ + basic.h basic.c \ + coproc.h coproc.c \ + simd.h simd.c \ special.h special.c -libarmv7registers_la_LIBADD = +libarmv7registers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libarmv7registers_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/arm/v7/registers/banked.c b/plugins/arm/v7/registers/banked.c index a74eca0..6e9fbf3 100644 --- a/plugins/arm/v7/registers/banked.c +++ b/plugins/arm/v7/registers/banked.c @@ -27,7 +27,7 @@ #include <stdio.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> #include "../register-int.h" @@ -78,14 +78,6 @@ static GArchRegister *_g_armv7_banked_register_new(BankedRegisterTarget); -/* --------------------- TRANSPOSITIONS VIA CACHE DES REGISTRES --------------------- */ - - -/* Charge un registre depuis une mémoire tampon. */ -static GArchRegister *g_armv7_banked_register_unserialize(GArmV7BankedRegister *, GAsmStorage *, packed_buffer *); - - - /* ------------------------ GESTION SOUS FORME DE SINGLETONS ------------------------ */ @@ -133,7 +125,6 @@ static void g_armv7_banked_register_class_init(GArmV7BankedRegisterClass *klass) object_class->finalize = (GObjectFinalizeFunc)g_armv7_banked_register_finalize; reg_class->print = (reg_print_fc)g_armv7_banked_register_print; - reg_class->unserialize = (reg_unserialize_fc)g_armv7_banked_register_unserialize; } @@ -567,63 +558,6 @@ BankedRegisterTarget g_armv7_banked_register_get_target(const GArmV7BankedRegist /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : reg = registre d'architecture à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un registre depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GArchRegister *g_armv7_banked_register_unserialize(GArmV7BankedRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) -{ - GArchRegister *result; /* Instance à retourner */ - uint8_t index; /* Indice du registre */ - bool status; /* Bilan d'une extraction */ - GArchRegisterClass *parent; /* Classe parente à consulter */ - - status = extract_packed_buffer(pbuf, &index, sizeof(uint8_t), false); - - if (status) - { - result = get_armv7_banked_register(index); - - if (result == NULL) - g_object_unref(G_OBJECT(reg)); - - } - - else - { - g_object_unref(G_OBJECT(reg)); - result = NULL; - } - - if (result != NULL) - { - parent = G_ARCH_REGISTER_CLASS(g_armv7_banked_register_parent_class); - - result = parent->unserialize(result, storage, pbuf); - - } - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ /* GESTION SOUS FORME DE SINGLETONS */ /* ---------------------------------------------------------------------------------- */ diff --git a/plugins/arm/v7/registers/basic.c b/plugins/arm/v7/registers/basic.c index dc491fe..358135b 100644 --- a/plugins/arm/v7/registers/basic.c +++ b/plugins/arm/v7/registers/basic.c @@ -27,7 +27,7 @@ #include <stdio.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> #include "../register-int.h" @@ -75,14 +75,6 @@ static GArchRegister *_g_armv7_basic_register_new(uint8_t); -/* --------------------- TRANSPOSITIONS VIA CACHE DES REGISTRES --------------------- */ - - -/* Charge un registre depuis une mémoire tampon. */ -static GArchRegister *g_armv7_basic_register_unserialize(GArmV7BasicRegister *, GAsmStorage *, packed_buffer *); - - - /* ------------------------ GESTION SOUS FORME DE SINGLETONS ------------------------ */ @@ -130,7 +122,6 @@ static void g_armv7_basic_register_class_init(GArmV7BasicRegisterClass *klass) object_class->finalize = (GObjectFinalizeFunc)g_armv7_basic_register_finalize; reg_class->print = (reg_print_fc)g_armv7_basic_register_print; - reg_class->unserialize = (reg_unserialize_fc)g_armv7_basic_register_unserialize; } @@ -302,63 +293,6 @@ GArchRegister *g_armv7_basic_register_new(uint8_t index) /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : reg = registre d'architecture à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un registre depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GArchRegister *g_armv7_basic_register_unserialize(GArmV7BasicRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) -{ - GArchRegister *result; /* Instance à retourner */ - uint8_t index; /* Indice du registre */ - bool status; /* Bilan d'une extraction */ - GArchRegisterClass *parent; /* Classe parente à consulter */ - - status = extract_packed_buffer(pbuf, &index, sizeof(uint8_t), false); - - if (status) - { - result = get_armv7_basic_register(index); - - if (result == NULL) - g_object_unref(G_OBJECT(reg)); - - } - - else - { - g_object_unref(G_OBJECT(reg)); - result = NULL; - } - - if (result != NULL) - { - parent = G_ARCH_REGISTER_CLASS(g_armv7_basic_register_parent_class); - - result = parent->unserialize(result, storage, pbuf); - - } - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ /* GESTION SOUS FORME DE SINGLETONS */ /* ---------------------------------------------------------------------------------- */ diff --git a/plugins/arm/v7/registers/coproc.c b/plugins/arm/v7/registers/coproc.c index 0190eef..5c256a7 100644 --- a/plugins/arm/v7/registers/coproc.c +++ b/plugins/arm/v7/registers/coproc.c @@ -27,7 +27,7 @@ #include <stdio.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> #include "../register-int.h" @@ -76,14 +76,6 @@ static GArchRegister *_g_armv7_cp_register_new(uint8_t); -/* --------------------- TRANSPOSITIONS VIA CACHE DES REGISTRES --------------------- */ - - -/* Charge un registre depuis une mémoire tampon. */ -static GArchRegister *g_armv7_cp_register_unserialize(GArmV7CpRegister *, GAsmStorage *, packed_buffer *); - - - /* ------------------------ GESTION SOUS FORME DE SINGLETONS ------------------------ */ @@ -131,7 +123,6 @@ static void g_armv7_cp_register_class_init(GArmV7CpRegisterClass *klass) object_class->finalize = (GObjectFinalizeFunc)g_armv7_cp_register_finalize; reg_class->print = (reg_print_fc)g_armv7_cp_register_print; - reg_class->unserialize = (reg_unserialize_fc)g_armv7_cp_register_unserialize; } @@ -282,63 +273,6 @@ GArchRegister *g_armv7_cp_register_new(uint8_t index) /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : reg = registre d'architecture à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un registre depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GArchRegister *g_armv7_cp_register_unserialize(GArmV7CpRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) -{ - GArchRegister *result; /* Instance à retourner */ - uint8_t index; /* Indice du registre */ - bool status; /* Bilan d'une extraction */ - GArchRegisterClass *parent; /* Classe parente à consulter */ - - status = extract_packed_buffer(pbuf, &index, sizeof(uint8_t), false); - - if (status) - { - result = get_armv7_cp_register(index); - - if (result == NULL) - g_object_unref(G_OBJECT(reg)); - - } - - else - { - g_object_unref(G_OBJECT(reg)); - result = NULL; - } - - if (result != NULL) - { - parent = G_ARCH_REGISTER_CLASS(g_armv7_cp_register_parent_class); - - result = parent->unserialize(result, storage, pbuf); - - } - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ /* GESTION SOUS FORME DE SINGLETONS */ /* ---------------------------------------------------------------------------------- */ diff --git a/plugins/arm/v7/registers/simd.c b/plugins/arm/v7/registers/simd.c index 957e2f9..8c8c653 100644 --- a/plugins/arm/v7/registers/simd.c +++ b/plugins/arm/v7/registers/simd.c @@ -28,7 +28,7 @@ #include <stdio.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> #include "../register-int.h" @@ -70,22 +70,21 @@ static void g_armv7_simd_register_dispose(GArmV7SIMDRegister *); /* Procède à la libération totale de la mémoire. */ static void g_armv7_simd_register_finalize(GArmV7SIMDRegister *); -/* Traduit un registre en version humainement lisible. */ -static void g_armv7_simd_register_print(const GArmV7SIMDRegister *, GBufferLine *); - /* Crée une réprésentation de registre SIMD ARMv7. */ static GArchRegister *_g_armv7_simd_register_new(SIMDRegisterMapping, uint8_t); -/* --------------------- TRANSPOSITIONS VIA CACHE DES REGISTRES --------------------- */ +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ +/* Traduit un registre en version humainement lisible. */ +static void g_armv7_simd_register_print(const GArmV7SIMDRegister *, GBufferLine *); -/* Charge un registre depuis une mémoire tampon. */ -static GArchRegister *g_armv7_simd_register_unserialize(GArmV7SIMDRegister *, GAsmStorage *, packed_buffer *); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_armv7_simd_register_load(GArmV7SIMDRegister *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un registre dans une mémoire tampon. */ -static bool g_armv7_simd_register_serialize(const GArmV7SIMDRegister *, GAsmStorage *, packed_buffer *); +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_armv7_simd_register_store(GArmV7SIMDRegister *, GObjectStorage *, packed_buffer_t *); @@ -126,20 +125,20 @@ G_DEFINE_TYPE(GArmV7SIMDRegister, g_armv7_simd_register, G_TYPE_ARMV7_REGISTER); static void g_armv7_simd_register_class_init(GArmV7SIMDRegisterClass *klass) { - GObjectClass *object_class; /* Autre version de la classe */ - GArchRegisterClass *reg_class; /* Classe de haut niveau */ + GObjectClass *object; /* Autre version de la classe */ + GArchRegisterClass *reg; /* Classe de haut niveau */ - object_class = G_OBJECT_CLASS(klass); + object = G_OBJECT_CLASS(klass); - object_class->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_simd_register_dispose; - object_class->finalize = (GObjectFinalizeFunc)g_armv7_simd_register_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_armv7_simd_register_dispose; + object->finalize = (GObjectFinalizeFunc)g_armv7_simd_register_finalize; - reg_class = G_ARCH_REGISTER_CLASS(klass); + reg = G_ARCH_REGISTER_CLASS(klass); - reg_class->print = (reg_print_fc)g_armv7_simd_register_print; - reg_class->unserialize = (reg_unserialize_fc)g_armv7_simd_register_unserialize; - reg_class->serialize = (reg_serialize_fc)g_armv7_simd_register_serialize; + reg->print = (reg_print_fc)g_armv7_simd_register_print; + reg->load = (load_register_fc)g_armv7_simd_register_load; + reg->store = (store_register_fc)g_armv7_simd_register_store; } @@ -202,50 +201,6 @@ static void g_armv7_simd_register_finalize(GArmV7SIMDRegister *reg) /****************************************************************************** * * -* Paramètres : reg = registre à transcrire. * -* line = ligne tampon où imprimer l'opérande donné. * -* * -* Description : Traduit un registre en version humainement lisible. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_armv7_simd_register_print(const GArmV7SIMDRegister *reg, GBufferLine *line) -{ - char key[MAX_REGNAME_LEN]; /* Mot clef principal */ - size_t klen; /* Taille de ce mot clef */ - - switch (reg->mapping) - { - case SRM_SINGLE_WORD: - klen = snprintf(key, MAX_REGNAME_LEN, "s%hhu", G_ARM_REGISTER(reg)->index); - break; - - case SRM_DOUBLE_WORD: - klen = snprintf(key, MAX_REGNAME_LEN, "d%hhu", G_ARM_REGISTER(reg)->index); - break; - - case SRM_QUAD_WORD: - klen = snprintf(key, MAX_REGNAME_LEN, "q%hhu", G_ARM_REGISTER(reg)->index); - break; - - default: - assert(false); - klen = snprintf(key, MAX_REGNAME_LEN, "x??"); - break; - - } - - g_buffer_line_append_text(line, DLC_ASSEMBLY, key, klen, RTT_REGISTER, NULL); - -} - - -/****************************************************************************** -* * * Paramètres : mapping = type de registre demandé. * * index = indice du registre correspondant. * * * @@ -328,57 +283,84 @@ GArchRegister *g_armv7_simd_register_new(SIMDRegisterMapping mapping, uint8_t in /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * -* Paramètres : reg = registre d'architecture à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : reg = registre à transcrire. * +* line = ligne tampon où imprimer l'opérande donné. * * * -* Description : Charge un registre depuis une mémoire tampon. * +* Description : Traduit un registre en version humainement lisible. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GArchRegister *g_armv7_simd_register_unserialize(GArmV7SIMDRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) +static void g_armv7_simd_register_print(const GArmV7SIMDRegister *reg, GBufferLine *line) { - GArchRegister *result; /* Instance à retourner */ - SIMDRegisterMapping mapping; /* Type de registre */ - bool status; /* Bilan d'une extraction */ - uint8_t index; /* Indice du registre */ - GArchRegisterClass *parent; /* Classe parente à consulter */ + char key[MAX_REGNAME_LEN]; /* Mot clef principal */ + size_t klen; /* Taille de ce mot clef */ - status = extract_packed_buffer(pbuf, &mapping, sizeof(SIMDRegisterMapping), true); + switch (reg->mapping) + { + case SRM_SINGLE_WORD: + klen = snprintf(key, MAX_REGNAME_LEN, "s%hhu", G_ARM_REGISTER(reg)->index); + break; - if (status) - status = extract_packed_buffer(pbuf, &index, sizeof(uint8_t), false); + case SRM_DOUBLE_WORD: + klen = snprintf(key, MAX_REGNAME_LEN, "d%hhu", G_ARM_REGISTER(reg)->index); + break; - if (status) - { - result = get_armv7_simd_register(mapping, index); + case SRM_QUAD_WORD: + klen = snprintf(key, MAX_REGNAME_LEN, "q%hhu", G_ARM_REGISTER(reg)->index); + break; - if (result == NULL) - g_object_unref(G_OBJECT(reg)); + default: + assert(false); + klen = snprintf(key, MAX_REGNAME_LEN, "x??"); + break; } - else - { - g_object_unref(G_OBJECT(reg)); - result = NULL; - } + g_buffer_line_append_text(line, DLC_ASSEMBLY, key, klen, RTT_REGISTER, NULL); - if (result != NULL) +} + + +/****************************************************************************** +* * +* Paramètres : reg = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * +* * +* Description : Charge un contenu depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_armv7_simd_register_load(GArmV7SIMDRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchRegisterClass *parent; /* Classe parente à consulter */ + uleb128_t value; /* Valeur à charger */ + + parent = G_ARCH_REGISTER_CLASS(g_armv7_simd_register_parent_class); + + result = parent->load(G_ARCH_REGISTER(reg), storage, pbuf); + + if (result) { - parent = G_ARCH_REGISTER_CLASS(g_armv7_simd_register_parent_class); + result = unpack_uleb128(&value, pbuf); - result = parent->unserialize(G_ARCH_REGISTER(reg), storage, pbuf); + if (result) + reg->mapping = value; } @@ -389,11 +371,11 @@ static GArchRegister *g_armv7_simd_register_unserialize(GArmV7SIMDRegister *reg, /****************************************************************************** * * -* Paramètres : reg = registre d'architecture à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : reg = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un registre dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -401,20 +383,17 @@ static GArchRegister *g_armv7_simd_register_unserialize(GArmV7SIMDRegister *reg, * * ******************************************************************************/ -static bool g_armv7_simd_register_serialize(const GArmV7SIMDRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_armv7_simd_register_store(GArmV7SIMDRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchRegisterClass *parent; /* Classe parente à consulter */ - result = extend_packed_buffer(pbuf, ®->mapping, sizeof(SIMDRegisterMapping), true); - - if (result) - { - parent = G_ARCH_REGISTER_CLASS(g_armv7_simd_register_parent_class); + parent = G_ARCH_REGISTER_CLASS(g_armv7_simd_register_parent_class); - result = parent->serialize(G_ARCH_REGISTER(reg), storage, pbuf); + result = parent->store(G_ARCH_REGISTER(reg), storage, pbuf); - } + if (result) + result = pack_uleb128((uleb128_t []){ reg->mapping }, pbuf); return result; diff --git a/plugins/arm/v7/registers/special.c b/plugins/arm/v7/registers/special.c index 8591239..1fc9eb5 100644 --- a/plugins/arm/v7/registers/special.c +++ b/plugins/arm/v7/registers/special.c @@ -27,7 +27,7 @@ #include <stdio.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> #include "../register-int.h" @@ -75,14 +75,6 @@ static GArchRegister *_g_armv7_special_register_new(SpecRegTarget); -/* --------------------- TRANSPOSITIONS VIA CACHE DES REGISTRES --------------------- */ - - -/* Charge un registre depuis une mémoire tampon. */ -static GArchRegister *g_armv7_special_register_unserialize(GArmV7SpecialRegister *, GAsmStorage *, packed_buffer *); - - - /* ------------------------ GESTION SOUS FORME DE SINGLETONS ------------------------ */ @@ -130,7 +122,6 @@ static void g_armv7_special_register_class_init(GArmV7SpecialRegisterClass *klas object_class->finalize = (GObjectFinalizeFunc)g_armv7_special_register_finalize; reg_class->print = (reg_print_fc)g_armv7_special_register_print; - reg_class->unserialize = (reg_unserialize_fc)g_armv7_special_register_unserialize; } @@ -326,63 +317,6 @@ GArchRegister *g_armv7_special_register_new(SpecRegTarget target) /* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : reg = registre d'architecture à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un registre depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static GArchRegister *g_armv7_special_register_unserialize(GArmV7SpecialRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) -{ - GArchRegister *result; /* Instance à retourner */ - uint8_t index; /* Indice du registre */ - bool status; /* Bilan d'une extraction */ - GArchRegisterClass *parent; /* Classe parente à consulter */ - - status = extract_packed_buffer(pbuf, &index, sizeof(uint8_t), false); - - if (status) - { - result = get_armv7_special_register(index); - - if (result == NULL) - g_object_unref(G_OBJECT(reg)); - - } - - else - { - g_object_unref(G_OBJECT(reg)); - result = NULL; - } - - if (result != NULL) - { - parent = G_ARCH_REGISTER_CLASS(g_armv7_special_register_parent_class); - - result = parent->unserialize(result, storage, pbuf); - - } - - return result; - -} - - - -/* ---------------------------------------------------------------------------------- */ /* GESTION SOUS FORME DE SINGLETONS */ /* ---------------------------------------------------------------------------------- */ diff --git a/plugins/bhash/Makefile.am b/plugins/bhash/Makefile.am index 45c5ee0..31daeb1 100644 --- a/plugins/bhash/Makefile.am +++ b/plugins/bhash/Makefile.am @@ -45,9 +45,11 @@ libbhash_la_SOURCES = \ tlsh.h tlsh.c \ rich.h rich.c -libbhash_la_LIBADD = \ +libbhash_la_LIBADD = \ $(PYTHON3_LIBADD) +libbhash_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libbhash_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -60,8 +62,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libbhash_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/bhash/core.c b/plugins/bhash/core.c index 91a0bf2..eb05893 100644 --- a/plugins/bhash/core.c +++ b/plugins/bhash/core.c @@ -24,16 +24,15 @@ #include "core.h" -#include <config.h> #include <plugins/self.h> -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS_ +#ifdef INCLUDE_PYTHON3_BINDINGS_ # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -63,7 +62,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS result = add_bhash_module_to_python_module(); #else result = true; diff --git a/plugins/bhash/python/Makefile.am b/plugins/bhash/python/Makefile.am index 822a716..6dd127c 100644 --- a/plugins/bhash/python/Makefile.am +++ b/plugins/bhash/python/Makefile.am @@ -1,21 +1,16 @@ noinst_LTLIBRARIES = libbhashpython.la -libbhashpython_la_SOURCES = \ - imphash.h imphash.c \ - module.h module.c \ - tlsh.h tlsh.c \ +libbhashpython_la_SOURCES = \ + imphash.h imphash.c \ + module.h module.c \ + tlsh.h tlsh.c \ rich.h rich.c -libbhashpython_la_LDFLAGS = +libbhashpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libbhashpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/bootimg/Makefile.am b/plugins/bootimg/Makefile.am index ada1e4e..623c555 100644 --- a/plugins/bootimg/Makefile.am +++ b/plugins/bootimg/Makefile.am @@ -35,15 +35,17 @@ PYTHON3_SUBDIRS = python endif -libbootimg_la_SOURCES = \ - core.h core.c \ - bootimg-def.h \ - format-int.h format-int.c \ +libbootimg_la_SOURCES = \ + core.h core.c \ + bootimg-def.h \ + format-int.h format-int.c \ format.h format.c -libbootimg_la_LIBADD = \ +libbootimg_la_LIBADD = \ $(PYTHON3_LIBADD) +libbootimg_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libbootimg_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -55,8 +57,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libbootimg_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/bootimg/core.c b/plugins/bootimg/core.c index 9c4bc45..25b21db 100644 --- a/plugins/bootimg/core.c +++ b/plugins/bootimg/core.c @@ -24,18 +24,17 @@ #include "core.h" -#include <config.h> #include <core/global.h> #include <plugins/self.h> #include "format.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS result = add_format_bootimg_module_to_python_module(); #else result = true; diff --git a/plugins/bootimg/format-int.h b/plugins/bootimg/format-int.h index 560841d..9662856 100644 --- a/plugins/bootimg/format-int.h +++ b/plugins/bootimg/format-int.h @@ -37,8 +37,6 @@ struct _GBootImgFormat { GKnownFormat parent; /* A laisser en premier */ - GBinContent *content; /* Contenu binaire à étudier */ - boot_img_hdr header; /* Entête du format */ }; diff --git a/plugins/bootimg/python/Makefile.am b/plugins/bootimg/python/Makefile.am index 1f11581..d39a521 100644 --- a/plugins/bootimg/python/Makefile.am +++ b/plugins/bootimg/python/Makefile.am @@ -1,20 +1,15 @@ noinst_LTLIBRARIES = libbootimgpython.la -libbootimgpython_la_SOURCES = \ - format.h format.c \ - module.h module.c \ +libbootimgpython_la_SOURCES = \ + format.h format.c \ + module.h module.c \ translate.h translate.c -libbootimgpython_la_LDFLAGS = +libbootimgpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libbootimgpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/bootimg/python/format.c b/plugins/bootimg/python/format.c index d5e32d3..273daee 100644 --- a/plugins/bootimg/python/format.c +++ b/plugins/bootimg/python/format.c @@ -95,7 +95,7 @@ static PyObject *py_bootimg_format_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -395,7 +395,10 @@ bool register_python_bootimg_format(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BOOTIMG_FORMAT, type, get_python_known_format_type())) + if (!ensure_python_known_format_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BOOTIMG_FORMAT, type)) return false; return true; diff --git a/plugins/dalvik/Makefile.am b/plugins/dalvik/Makefile.am index 644c38a..62ee8a6 100644 --- a/plugins/dalvik/Makefile.am +++ b/plugins/dalvik/Makefile.am @@ -39,26 +39,28 @@ PYTHON3_SUBDIRS = python endif -libdalvik_la_SOURCES = \ - context.h context.c \ - core.h core.c \ - fetch.h fetch.c \ - helpers.h \ - instruction-int.h \ - instruction.h instruction.c \ - link.h link.c \ - operand.h operand.c \ - post.h post.c \ - processor-int.h \ - processor.h processor.c \ +libdalvik_la_SOURCES = \ + context.h context.c \ + core.h core.c \ + fetch.h fetch.c \ + helpers.h \ + instruction-int.h \ + instruction.h instruction.c \ + link.h link.c \ + operand.h operand.c \ + post.h post.c \ + processor-int.h \ + processor.h processor.c \ register.h register.c -libdalvik_la_LIBADD = \ - operands/libdalvikoperands.la \ - pseudo/libdalvikpseudo.la \ - $(PYTHON3_LIBADD) \ +libdalvik_la_LIBADD = \ + operands/libdalvikoperands.la \ + pseudo/libdalvikpseudo.la \ + $(PYTHON3_LIBADD) \ v35/libdalvik35.la +libdalvik_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libdalvik_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -71,9 +73,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdalvik_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - SUBDIRS = operands pseudo $(PYTHON3_SUBDIRS) v35 diff --git a/plugins/dalvik/context.c b/plugins/dalvik/context.c index b08678c..9cf878b 100644 --- a/plugins/dalvik/context.c +++ b/plugins/dalvik/context.c @@ -373,7 +373,7 @@ bool g_dalvik_context_register_array_data_padding(GDalvikContext *ctx, const vmp * * ******************************************************************************/ -GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *ctx, const GBinContent *content, vmpa2t *pos) +GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *ctx, GBinContent *content, vmpa2t *pos) { GArchInstruction *result; /* Instruction à retourner */ raw_data_area *found; /* Zone de couverture trouvée */ @@ -390,7 +390,7 @@ GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *ctx, const GBinC if (found) { - restricted = g_restricted_content_new_ro(content, &found->range); + restricted = g_restricted_content_new(content, &found->range); length = get_mrange_length(&found->range); count = length / found->item_len; diff --git a/plugins/dalvik/context.h b/plugins/dalvik/context.h index bfa2757..f09cfa6 100644 --- a/plugins/dalvik/context.h +++ b/plugins/dalvik/context.h @@ -67,7 +67,7 @@ bool g_dalvik_context_register_array_data(GDalvikContext *, const vmpa2t *, uint bool g_dalvik_context_register_array_data_padding(GDalvikContext *, const vmpa2t *); /* Place une donnée en tant qu'instruction si besoin est. */ -GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *, const GBinContent *, vmpa2t *); +GArchInstruction *g_dalvik_context_get_raw_data(GDalvikContext *, GBinContent *, vmpa2t *); diff --git a/plugins/dalvik/core.c b/plugins/dalvik/core.c index 2294ed4..8344825 100644 --- a/plugins/dalvik/core.c +++ b/plugins/dalvik/core.c @@ -24,7 +24,6 @@ #include "core.h" -#include <config.h> #include <plugins/self.h> @@ -32,13 +31,13 @@ #include "operands/args.h" #include "operands/pool.h" #include "operands/register.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif #include "v35/core.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -100,7 +99,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) result = init_dalvik35_core(); -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS if (result) result = add_arch_dalvik_module_to_python_module(); #endif diff --git a/plugins/dalvik/operand.c b/plugins/dalvik/operand.c index a176721..4db8fa9 100644 --- a/plugins/dalvik/operand.c +++ b/plugins/dalvik/operand.c @@ -749,7 +749,7 @@ void dalvik_mark_first_operand_as_written(GArchInstruction *instr) operand = g_arch_instruction_get_operand(instr, 0); - g_register_operand_mark_as_written(G_REGISTER_OPERAND(operand)); + g_arch_operand_set_flag(operand, ROF_IS_WRITTEN); g_object_unref(G_OBJECT(operand)); diff --git a/plugins/dalvik/operands/Makefile.am b/plugins/dalvik/operands/Makefile.am index 4ce597a..3a4ddc1 100644 --- a/plugins/dalvik/operands/Makefile.am +++ b/plugins/dalvik/operands/Makefile.am @@ -1,20 +1,14 @@ noinst_LTLIBRARIES = libdalvikoperands.la -libdalvikoperands_la_SOURCES = \ - args.h args.c \ - pool.h pool.c \ +libdalvikoperands_la_SOURCES = \ + args.h args.c \ + pool.h pool.c \ register.h register.c +libdalvikoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdalvikoperands_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - -SUBDIRS = diff --git a/plugins/dalvik/operands/args.c b/plugins/dalvik/operands/args.c index 4b87e5e..64f8eea 100644 --- a/plugins/dalvik/operands/args.c +++ b/plugins/dalvik/operands/args.c @@ -32,11 +32,14 @@ #include <arch/operand-int.h> #include <common/sort.h> +#include <core/columns.h> #include <core/logs.h> -#include <gtkext/gtkblockdisplay.h> +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + /* Définition d'un opérande visant une liste d'opérandes Dalvik (instance) */ struct _GDalvikArgsOperand { @@ -68,8 +71,13 @@ static void g_dalvik_args_operand_dispose(GDalvikArgsOperand *); /* Procède à la libération totale de la mémoire. */ static void g_dalvik_args_operand_finalize(GDalvikArgsOperand *); + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + /* Compare un opérande avec un autre. */ -static int g_dalvik_args_operand_compare(const GDalvikArgsOperand *, const GDalvikArgsOperand *); +static int g_dalvik_args_operand_compare(const GDalvikArgsOperand *, const GDalvikArgsOperand *, bool); /* Détermine le chemin conduisant à un opérande interne. */ static char *g_dalvik_args_operand_find_inner_operand_path(const GDalvikArgsOperand *, const GArchOperand *); @@ -80,17 +88,20 @@ static GArchOperand *g_dalvik_args_operand_get_inner_operand_from_path(const GDa /* Traduit un opérande en version humainement lisible. */ static void g_dalvik_args_operand_print(const GDalvikArgsOperand *, GBufferLine *); +/* Fournit une liste de candidats embarqués par un candidat. */ +static GArchOperand **g_dalvik_args_operand_list_inner_instances(const GDalvikArgsOperand *, size_t *); +/* Met à jour une liste de candidats embarqués par un candidat. */ +static void g_dalvik_args_operand_update_inner_instances(GDalvikArgsOperand *, GArchOperand **, size_t); -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ - +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_dalvik_args_operand_hash(const GDalvikArgsOperand *, bool); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_dalvik_args_operand_unserialize(GDalvikArgsOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_dalvik_args_operand_serialize(const GDalvikArgsOperand *, GAsmStorage *, packed_buffer *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ /* Indique le type défini par la GLib pour une liste d'arguments Dalvik. */ @@ -127,8 +138,12 @@ static void g_dalvik_args_operand_class_init(GDalvikArgsOperandClass *klass) operand->print = (operand_print_fc)g_dalvik_args_operand_print; - operand->unserialize = (unserialize_operand_fc)g_dalvik_args_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_dalvik_args_operand_serialize; + operand->list_inner = (operand_list_inners_fc)g_dalvik_args_operand_list_inner_instances; + operand->update_inner = (operand_update_inners_fc)g_dalvik_args_operand_update_inner_instances; + operand->hash = (operand_hash_fc)g_dalvik_args_operand_hash; + + operand->load = g_arch_operand_load_generic_variadic; + operand->store = g_arch_operand_store_generic_variadic; } @@ -170,7 +185,7 @@ static void g_dalvik_args_operand_dispose(GDalvikArgsOperand *operand) size_t i; for (i = 0; i < operand->count; i++) - g_object_unref(G_OBJECT(operand->args[i])); + g_clear_object(&operand->args[i]); G_OBJECT_CLASS(g_dalvik_args_operand_parent_class)->dispose(G_OBJECT(operand)); @@ -201,8 +216,102 @@ static void g_dalvik_args_operand_finalize(GDalvikArgsOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : - * +* * +* Description : Crée un réceptacle pour opérandes Dalvik servant d'arguments.* +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_dalvik_args_operand_new(void) +{ + GArchOperand *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_DALVIK_ARGS_OPERAND, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à compléter. * +* arg = nouvel argument pour un appel. * +* * +* Description : Ajoute un élément à la liste d'arguments Dalvik. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_dalvik_args_operand_add(GDalvikArgsOperand *operand, GArchOperand *arg) +{ + operand->count++; + operand->args = realloc(operand->args, operand->count * sizeof(GArchOperand *)); + + operand->args[operand->count - 1] = arg; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à compléter. * +* * +* Description : Fournit le nombre d'arguments pris en charge. * +* * +* Retour : Nombre positif ou nul. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_dalvik_args_count(const GDalvikArgsOperand *operand) +{ + return operand->count; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à compléter. * +* index = indice de l'argument recherché. * +* * +* Description : Founit un élément de la liste d'arguments Dalvik. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_dalvik_args_operand_get(const GDalvikArgsOperand *operand, size_t index) +{ + assert(index < operand->count); + + return operand->args[index]; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -212,10 +321,13 @@ static void g_dalvik_args_operand_finalize(GDalvikArgsOperand *operand) * * ******************************************************************************/ -static int g_dalvik_args_operand_compare(const GDalvikArgsOperand *a, const GDalvikArgsOperand *b) +static int g_dalvik_args_operand_compare(const GDalvikArgsOperand *a, const GDalvikArgsOperand *b, bool lock) { int result; /* Bilan à renvoyer */ + operand_extra_data_t *ea; /* Données insérées à consulter*/ + operand_extra_data_t *eb; /* Données insérées à consulter*/ size_t i; /* Boucle de parcours */ + GArchOperandClass *class; /* Classe parente normalisée */ /* Création de l'objet... */ if (b == NULL) @@ -223,11 +335,32 @@ static int g_dalvik_args_operand_compare(const GDalvikArgsOperand *a, const GDal else { + ea = GET_ARCH_OP_EXTRA(G_ARCH_OPERAND(a)); + eb = GET_ARCH_OP_EXTRA(G_ARCH_OPERAND(b)); + + if (lock) + { + LOCK_GOBJECT_EXTRA(ea); + LOCK_GOBJECT_EXTRA(eb); + } + result = sort_unsigned_long(a->count, b->count); for (i = 0; i < a->count && result == 0; i++) result = g_arch_operand_compare(a->args[i], b->args[i]); + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_dalvik_args_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } + + if (lock) + { + UNLOCK_GOBJECT_EXTRA(eb); + UNLOCK_GOBJECT_EXTRA(ea); + } + } return result; @@ -398,75 +531,44 @@ static void g_dalvik_args_operand_print(const GDalvikArgsOperand *operand, GBuff /****************************************************************************** * * -* Paramètres : - * +* Paramètres : operand = objet dont l'instance se veut unique. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Crée un réceptacle pour opérandes Dalvik servant d'arguments.* +* Description : Fournit une liste de candidats embarqués par un candidat. * * * -* Retour : Opérande mis en place. * +* Retour : Liste de candidats internes ou NULL si aucun. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_dalvik_args_operand_new(void) +static GArchOperand **g_dalvik_args_operand_list_inner_instances(const GDalvikArgsOperand *operand, size_t *count) { - GArchOperand *result; /* Structure à retourner */ - - result = g_object_new(G_TYPE_DALVIK_ARGS_OPERAND, NULL); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : operand = opérande à compléter. * -* arg = nouvel argument pour un appel. * -* * -* Description : Ajoute un élément à la liste d'arguments Dalvik. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_dalvik_args_operand_add(GDalvikArgsOperand *operand, GArchOperand *arg) -{ - operand->count++; - operand->args = (GArchOperand **)realloc(operand->args, operand->count * sizeof(GArchOperand *)); - - operand->args[operand->count - 1] = arg; + GArchOperand **result; /* Instances à retourner */ + size_t i; /* Boucle de parcours */ -} + *count = operand->count; + result = malloc(*count * sizeof(GArchOperand *)); -/****************************************************************************** -* * -* Paramètres : operand = opérande à compléter. * -* * -* Description : Fournit le nombre d'arguments pris en charge. * -* * -* Retour : Nombre positif ou nul. * -* * -* Remarques : - * -* * -******************************************************************************/ + for (i = 0; i < *count; i++) + { + result[i] = operand->args[i]; + g_object_ref(G_OBJECT(result[i])); + } -size_t g_dalvik_args_count(const GDalvikArgsOperand *operand) -{ - return operand->count; + return result; } /****************************************************************************** * * -* Paramètres : operand = opérande à compléter. * -* index = indice de l'argument recherché. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* instances = liste de candidats internes devenus singletons. * +* count = quantité d'instances à l'unicité internes. * * * -* Description : Founit un élément de la liste d'arguments Dalvik. * +* Description : Met à jour une liste de candidats embarqués par un candidat. * * * * Retour : - * * * @@ -474,97 +576,56 @@ size_t g_dalvik_args_count(const GDalvikArgsOperand *operand) * * ******************************************************************************/ -GArchOperand *g_dalvik_args_operand_get(const GDalvikArgsOperand *operand, size_t index) +static void g_dalvik_args_operand_update_inner_instances(GDalvikArgsOperand *operand, GArchOperand **instances, size_t count) { - assert(index < operand->count); - - return operand->args[index]; - -} - - - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un opérande depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_dalvik_args_operand_unserialize(GDalvikArgsOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) -{ - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - size_t count; /* Nombre d'opérandes à charger*/ size_t i; /* Boucle de parcours */ - GArchOperand *arg; /* Nouvel argument à intégrer */ - parent = G_ARCH_OPERAND_CLASS(g_dalvik_args_operand_parent_class); - - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); + for (i = 0; i < count; i++) + g_object_unref(G_OBJECT(operand->args[i])); - if (result) - result = extract_packed_buffer(pbuf, &count, sizeof(size_t), true); + operand->count = count; + operand->args = realloc(operand->args, operand->count * sizeof(GArchOperand *)); - for (i = 0; i < count && result; i++) + for (i = 0; i < count; i++) { - arg = g_arch_operand_load(storage, format, pbuf); - - if (arg == NULL) - result = false; - - else - g_dalvik_args_operand_add(operand, arg); - + operand->args[i] = instances[i]; + g_object_ref(G_OBJECT(instances[i])); } - return result; - } /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * * * -* Retour : Bilan de l'opération. * +* Retour : Empreinte de l'élément représenté. * * * * Remarques : - * * * ******************************************************************************/ -static bool g_dalvik_args_operand_serialize(const GDalvikArgsOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static guint g_dalvik_args_operand_hash(const GDalvikArgsOperand *operand, bool lock) { - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ - size_t i; /* Boucle de parcours */ + guint result; /* Valeur à retourner */ + operand_extra_data_t *extra; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + + extra = GET_ARCH_OP_EXTRA(G_ARCH_OPERAND(operand)); - parent = G_ARCH_OPERAND_CLASS(g_dalvik_args_operand_parent_class); + if (lock) + LOCK_GOBJECT_EXTRA(extra); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + class = G_ARCH_OPERAND_CLASS(g_dalvik_args_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); - if (result) - result = extend_packed_buffer(pbuf, &operand->count, sizeof(size_t), true); + result ^= operand->count; - for (i = 0; i < operand->count && result; i++) - result = g_arch_operand_store(operand->args[i], storage, pbuf); + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); return result; diff --git a/plugins/dalvik/operands/pool.c b/plugins/dalvik/operands/pool.c index 6f16cdc..5b99b45 100644 --- a/plugins/dalvik/operands/pool.c +++ b/plugins/dalvik/operands/pool.c @@ -34,18 +34,30 @@ #include <arch/operand-int.h> #include <arch/operands/targetable-int.h> #include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> #include <plugins/dex/pool.h> +/* -------------------------- DEFINITION D'UN NOUVEAU TYPE -------------------------- */ + + +/* Informations glissées dans la structure GObject de GArchOperand */ +typedef struct _dpoolop_extra_data_t +{ + operand_extra_data_t parent; /* A laisser en premier */ + + DalvikPoolType type; /* Type de table visée */ + +} dpoolop_extra_data_t; + + /* Définition d'un opérande visant un élément de table de constantes Dalvik (instance) */ struct _GDalvikPoolOperand { GArchOperand parent; /* Instance parente */ GDexFormat *format; /* Lien vers le contenu réel */ - DalvikPoolType type; /* Type de table visée */ uint32_t index; /* Indice de l'élément visé */ }; @@ -59,6 +71,21 @@ struct _GDalvikPoolOperandClass }; +/** + * Accès aux informations éventuellement déportées. + */ + +#if 1 //__SIZEOF_INT__ == __SIZEOF_LONG__ + +# define GET_DALVIK_POOL_OP_EXTRA(op) ((dpoolop_extra_data_t *)&((GArchOperand *)op)->extra) + +#else + +# define GET_DALVIK_POOL_OP_EXTRA(op) GET_GOBJECT_EXTRA(G_OBJECT(op), dpoolop_extra_data_t) + +#endif + + /* Initialise la classe des opérandes de constante Dalvik. */ static void g_dalvik_pool_operand_class_init(GDalvikPoolOperandClass *); @@ -74,22 +101,28 @@ static void g_dalvik_pool_operand_dispose(GDalvikPoolOperand *); /* Procède à la libération totale de la mémoire. */ static void g_dalvik_pool_operand_finalize(GDalvikPoolOperand *); -/* Compare un opérande avec un autre. */ -static int g_dalvik_pool_operand_compare(const GDalvikPoolOperand *, const GDalvikPoolOperand *); +/* Indique la nature de la table de constantes visée ici. */ +static DalvikPoolType _g_dalvik_pool_operand_get_pool_type(const GDalvikPoolOperand *, bool); + -/* Traduit un opérande en version humainement lisible. */ -static void g_dalvik_pool_operand_print(const GDalvikPoolOperand *, GBufferLine *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* --------------------- TRANSPOSITIONS VIA CACHE DES OPERANDES --------------------- */ +/* Compare un opérande avec un autre. */ +static int g_dalvik_pool_operand_compare(const GDalvikPoolOperand *, const GDalvikPoolOperand *, bool); + +/* Traduit un opérande en version humainement lisible. */ +static void g_dalvik_pool_operand_print(const GDalvikPoolOperand *, GBufferLine *); +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint g_dalvik_pool_operand_hash(const GDalvikPoolOperand *, bool); -/* Charge un opérande depuis une mémoire tampon. */ -static bool g_dalvik_pool_operand_unserialize(GDalvikPoolOperand *, GAsmStorage *, GBinFormat *, packed_buffer *); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_dalvik_pool_operand_load(GDalvikPoolOperand *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un opérande dans une mémoire tampon. */ -static bool g_dalvik_pool_operand_serialize(const GDalvikPoolOperand *, GAsmStorage *, packed_buffer *); +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_dalvik_pool_operand_store(GDalvikPoolOperand *, GObjectStorage *, packed_buffer_t *); @@ -101,6 +134,11 @@ static bool g_dalvik_pool_operand_get_addr(const GDalvikPoolOperand *, const vmp +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UN NOUVEAU TYPE */ +/* ---------------------------------------------------------------------------------- */ + + /* Indique le type défini par la GLib pour un un élément de table de constantes Dalvik. */ G_DEFINE_TYPE_WITH_CODE(GDalvikPoolOperand, g_dalvik_pool_operand, G_TYPE_ARCH_OPERAND, G_IMPLEMENT_INTERFACE(G_TYPE_TARGETABLE_OPERAND, g_dalvik_pool_operand_targetable_interface_init)); @@ -133,8 +171,10 @@ static void g_dalvik_pool_operand_class_init(GDalvikPoolOperandClass *klass) operand->compare = (operand_compare_fc)g_dalvik_pool_operand_compare; operand->print = (operand_print_fc)g_dalvik_pool_operand_print; - operand->unserialize = (unserialize_operand_fc)g_dalvik_pool_operand_unserialize; - operand->serialize = (serialize_operand_fc)g_dalvik_pool_operand_serialize; + operand->hash = (operand_hash_fc)g_dalvik_pool_operand_hash; + + operand->load = (load_operand_fc)g_dalvik_pool_operand_load; + operand->store = (store_operand_fc)g_dalvik_pool_operand_store; } @@ -191,8 +231,7 @@ static void g_dalvik_pool_operand_targetable_interface_init(GTargetableOperandIn static void g_dalvik_pool_operand_dispose(GDalvikPoolOperand *operand) { - if (operand->format != NULL) - g_object_unref(G_OBJECT(operand->format)); + g_clear_object(&operand->format); G_OBJECT_CLASS(g_dalvik_pool_operand_parent_class)->dispose(G_OBJECT(operand)); @@ -220,8 +259,155 @@ static void g_dalvik_pool_operand_finalize(GDalvikPoolOperand *operand) /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : format = format du fichier contenant le code. * +* type = type de table visée avec la référence. * +* content = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* size = taille de l'opérande, et donc du registre. * +* endian = ordre des bits dans la source. * +* * +* Description : Crée un opérande visant un élément constant Dalvik. * +* * +* Retour : Opérande mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GArchOperand *g_dalvik_pool_operand_new(GDexFormat *format, DalvikPoolType type, const GBinContent *content, vmpa2t *pos, MemoryDataSize size, SourceEndian endian) +{ + GDalvikPoolOperand *result; /* Structure à retourner */ + uint16_t index16; /* Indice sur 16 bits */ + uint32_t index32; /* Indice sur 32 bits */ + bool test; /* Bilan de lecture */ + dpoolop_extra_data_t *extra; /* Données insérées à modifier */ + + switch (size) + { + case MDS_16_BITS: + test = g_binary_content_read_u16(content, pos, endian, &index16); + break; + case MDS_32_BITS: + test = g_binary_content_read_u32(content, pos, endian, &index32); + break; + default: + test = false; + break; + } + + if (!test) + goto gdpon_exit; + + result = g_object_new(G_TYPE_DALVIK_POOL_OPERAND, NULL); + + extra = GET_DALVIK_POOL_OP_EXTRA(result); + + extra->type = type; + + result->format = format; + g_object_ref(G_OBJECT(format)); + + result->index = (size == MDS_16_BITS ? index16 : index32); + + return G_ARCH_OPERAND(result); + + gdpon_exit: + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* lock = précise le besoin en verrouillage. * +* * +* Description : Indique la nature de la table de constantes visée ici. * +* * +* Retour : Type de table constantes visée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static DalvikPoolType _g_dalvik_pool_operand_get_pool_type(const GDalvikPoolOperand *operand, bool lock) +{ + DalvikPoolType result; /* Type à retourner */ + dpoolop_extra_data_t *extra; /* Données insérées à consulter*/ + + extra = GET_DALVIK_POOL_OP_EXTRA(operand); + + if (lock) + LOCK_GOBJECT_EXTRA(extra); + + result = extra->type; + + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Indique la nature de la table de constantes visée ici. * +* * +* Retour : Type de table constantes visée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +DalvikPoolType g_dalvik_pool_operand_get_pool_type(const GDalvikPoolOperand *operand) +{ + DalvikPoolType result; /* Type à retourner */ + + result = _g_dalvik_pool_operand_get_pool_type(operand, true); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : operand = opérande à consulter. * +* * +* Description : Indique l'indice de l'élément dans la table de constantes. * +* * +* Retour : Indice de l'élément visé dans la table de constantes. * +* * +* Remarques : - * +* * +******************************************************************************/ + +uint32_t g_dalvik_pool_operand_get_index(const GDalvikPoolOperand *operand) +{ + uint32_t result; /* Indice à retourner */ + + result = operand->index; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -231,18 +417,42 @@ static void g_dalvik_pool_operand_finalize(GDalvikPoolOperand *operand) * * ******************************************************************************/ -static int g_dalvik_pool_operand_compare(const GDalvikPoolOperand *a, const GDalvikPoolOperand *b) +static int g_dalvik_pool_operand_compare(const GDalvikPoolOperand *a, const GDalvikPoolOperand *b, bool lock) { int result; /* Bilan à renvoyer */ + dpoolop_extra_data_t *ea; /* Données insérées à consulter*/ + dpoolop_extra_data_t *eb; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + + ea = GET_DALVIK_POOL_OP_EXTRA(a); + eb = GET_DALVIK_POOL_OP_EXTRA(b); + + if (lock) + { + LOCK_GOBJECT_EXTRA(ea); + LOCK_GOBJECT_EXTRA(eb); + } result = sort_unsigned_long((unsigned long)a->format, (unsigned long)b->format); if (result == 0) - result = sort_unsigned_long(a->type, b->type); + result = sort_unsigned_long(ea->type, eb->type); if (result == 0) result = sort_unsigned_long(a->index, b->index); + if (result == 0) + { + class = G_ARCH_OPERAND_CLASS(g_dalvik_pool_operand_parent_class); + result = class->compare(G_ARCH_OPERAND(a), G_ARCH_OPERAND(b), false); + } + + if (lock) + { + UNLOCK_GOBJECT_EXTRA(eb); + UNLOCK_GOBJECT_EXTRA(ea); + } + return result; } @@ -264,6 +474,7 @@ static int g_dalvik_pool_operand_compare(const GDalvikPoolOperand *a, const GDal static void g_dalvik_pool_operand_print(const GDalvikPoolOperand *operand, GBufferLine *line) { GDexPool *pool; /* Table de ressources */ + DalvikPoolType pool_type; /* Type de table visé */ const char *string; /* Chaîne de caractères #1 */ GDataType *type; /* Type à représenter */ size_t len; /* Taille du texte à créer */ @@ -274,7 +485,9 @@ static void g_dalvik_pool_operand_print(const GDalvikPoolOperand *operand, GBuff pool = g_dex_format_get_pool(operand->format); - switch (operand->type) + pool_type = g_dalvik_pool_operand_get_pool_type(operand); + + switch (pool_type) { case DPT_NONE: g_buffer_line_append_text(line, DLC_ASSEMBLY, "????", 4, RTT_ERROR, NULL); @@ -435,140 +648,102 @@ static void g_dalvik_pool_operand_print(const GDalvikPoolOperand *operand, GBuff /****************************************************************************** * * -* Paramètres : format = format du fichier contenant le code. * -* type = type de table visée avec la référence. * -* content = flux de données à analyser. * -* pos = position courante dans ce flux. [OUT] * -* size = taille de l'opérande, et donc du registre. * -* endian = ordre des bits dans la source. * +* Paramètres : operand = objet dont l'instance se veut unique. * +* lock = précise le besoin en verrouillage. * * * -* Description : Crée un opérande visant un élément constant Dalvik. * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * * * -* Retour : Opérande mis en place. * +* Retour : Empreinte de l'élément représenté. * * * * Remarques : - * * * ******************************************************************************/ -GArchOperand *g_dalvik_pool_operand_new(GDexFormat *format, DalvikPoolType type, const GBinContent *content, vmpa2t *pos, MemoryDataSize size, SourceEndian endian) +static guint g_dalvik_pool_operand_hash(const GDalvikPoolOperand *operand, bool lock) { - GDalvikPoolOperand *result; /* Structure à retourner */ - uint16_t index16; /* Indice sur 16 bits */ - uint32_t index32; /* Indice sur 32 bits */ - bool test; /* Bilan de lecture */ - - switch (size) - { - case MDS_16_BITS: - test = g_binary_content_read_u16(content, pos, endian, &index16); - break; - case MDS_32_BITS: - test = g_binary_content_read_u32(content, pos, endian, &index32); - break; - default: - test = false; - break; - } - - if (!test) - goto gdpon_exit; + guint result; /* Valeur à retourner */ + dpoolop_extra_data_t *extra; /* Données insérées à consulter*/ + GArchOperandClass *class; /* Classe parente normalisée */ + DalvikPoolType type; /* Type porté par l'opérande */ + uint32_t index; /* Indice de l'élément */ - result = g_object_new(G_TYPE_DALVIK_POOL_OPERAND, NULL); + extra = GET_DALVIK_POOL_OP_EXTRA(G_DALVIK_POOL_OPERAND(operand)); - g_object_ref(G_OBJECT(format)); + if (lock) + LOCK_GOBJECT_EXTRA(extra); - result->format = format; - result->type = type; - result->index = (size == MDS_16_BITS ? index16 : index32); + class = G_ARCH_OPERAND_CLASS(g_dalvik_pool_operand_parent_class); + result = class->hash(G_ARCH_OPERAND(operand), false); - return G_ARCH_OPERAND(result); + result ^= g_direct_hash(operand->format); - gdpon_exit: + type = _g_dalvik_pool_operand_get_pool_type(operand, !lock); - return NULL; + result ^= type; -} + index = g_dalvik_pool_operand_get_index(operand); + result ^= index; -/****************************************************************************** -* * -* Paramètres : operand = opérande à consulter. * -* * -* Description : Indique la nature de la table de constantes visée ici. * -* * -* Retour : Type de table constantes visée. * -* * -* Remarques : - * -* * -******************************************************************************/ + if (lock) + UNLOCK_GOBJECT_EXTRA(extra); -DalvikPoolType g_dalvik_pool_operand_get_pool_type(const GDalvikPoolOperand *operand) -{ - return operand->type; + return result; } /****************************************************************************** * * -* Paramètres : operand = opérande à consulter. * +* Paramètres : operand = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * * * -* Description : Indique l'indice de l'élément dans la table de constantes. * +* Description : Charge un contenu depuis une mémoire tampon. * * * -* Retour : Indice de l'élément visé dans la table de constantes. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -uint32_t g_dalvik_pool_operand_get_index(const GDalvikPoolOperand *operand) +static bool g_dalvik_pool_operand_load(GDalvikPoolOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { - return operand->index; - -} + bool result; /* Bilan à retourner */ + GArchOperandClass *parent; /* Classe parente à consulter */ + dpoolop_extra_data_t *extra; /* Données insérées à modifier */ + uleb128_t value; /* Valeur ULEB128 à charger */ + parent = G_ARCH_OPERAND_CLASS(g_dalvik_pool_operand_parent_class); + result = parent->load(G_ARCH_OPERAND(operand), storage, pbuf); -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ + if (result) + { + extra = GET_DALVIK_POOL_OP_EXTRA(operand); + LOCK_GOBJECT_EXTRA(extra); -/****************************************************************************** -* * -* Paramètres : operand = opérande d'assemblage à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* format = format binaire chargé associé à l'architecture. * -* pbuf = zone tampon à remplir. * -* * -* Description : Charge un opérande depuis une mémoire tampon. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ + result = unpack_uleb128(&value, pbuf); -static bool g_dalvik_pool_operand_unserialize(GDalvikPoolOperand *operand, GAsmStorage *storage, GBinFormat *format, packed_buffer *pbuf) -{ - bool result; /* Bilan à retourner */ - GArchOperandClass *parent; /* Classe parente à consulter */ + if (result) + extra->type = value; - parent = G_ARCH_OPERAND_CLASS(g_dalvik_pool_operand_parent_class); + UNLOCK_GOBJECT_EXTRA(extra); - result = parent->unserialize(G_ARCH_OPERAND(operand), storage, format, pbuf); + } if (result) { - operand->format = G_DEX_FORMAT(format); - g_object_ref(G_OBJECT(format)); + operand->format = get_storage_linked_format(storage); + result = G_IS_DEX_FORMAT(operand->format); } if (result) - result = extract_packed_buffer(pbuf, &operand->type, sizeof(DalvikPoolType), true); + result = unpack_uleb128(&value, pbuf); if (result) - result = extract_packed_buffer(pbuf, &operand->index, sizeof(uint32_t), true); + operand->index = value; return result; @@ -577,11 +752,11 @@ static bool g_dalvik_pool_operand_unserialize(GDalvikPoolOperand *operand, GAsmS /****************************************************************************** * * -* Paramètres : operand = opérande d'assemblage à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : operand = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un opérande dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -589,20 +764,30 @@ static bool g_dalvik_pool_operand_unserialize(GDalvikPoolOperand *operand, GAsmS * * ******************************************************************************/ -static bool g_dalvik_pool_operand_serialize(const GDalvikPoolOperand *operand, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_dalvik_pool_operand_store(GDalvikPoolOperand *operand, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchOperandClass *parent; /* Classe parente à consulter */ + dpoolop_extra_data_t *extra; /* Données insérées à modifier */ parent = G_ARCH_OPERAND_CLASS(g_dalvik_pool_operand_parent_class); - result = parent->serialize(G_ARCH_OPERAND(operand), storage, pbuf); + result = parent->store(G_ARCH_OPERAND(operand), storage, pbuf); if (result) - result = extend_packed_buffer(pbuf, &operand->type, sizeof(DalvikPoolType), true); + { + extra = GET_DALVIK_POOL_OP_EXTRA(operand); + + LOCK_GOBJECT_EXTRA(extra); + + result = pack_uleb128((uleb128_t []){ extra->type }, pbuf); + + UNLOCK_GOBJECT_EXTRA(extra); + + } if (result) - result = extend_packed_buffer(pbuf, &operand->index, sizeof(uint32_t), true); + result = pack_uleb128((uleb128_t []){ operand->index }, pbuf); return result; @@ -634,6 +819,7 @@ static bool g_dalvik_pool_operand_serialize(const GDalvikPoolOperand *operand, G static bool g_dalvik_pool_operand_get_addr(const GDalvikPoolOperand *operand, const vmpa2t *src, GBinFormat *format, GArchProcessor *proc, vmpa2t *addr) { bool result; /* Bilan à retourner */ + DalvikPoolType type; /* Type de table visé */ GDexPool *pool; /* Table de ressources */ GDexMethod *method; /* Méthode ciblée ici */ GBinRoutine *routine; /* Routine liée à la méthode */ @@ -641,7 +827,9 @@ static bool g_dalvik_pool_operand_get_addr(const GDalvikPoolOperand *operand, co result = false; - if (operand->type == DPT_METHOD) + type = g_dalvik_pool_operand_get_pool_type(operand); + + if (type == DPT_METHOD) { pool = g_dex_format_get_pool(G_DEX_FORMAT(format)); diff --git a/plugins/dalvik/pseudo/Makefile.am b/plugins/dalvik/pseudo/Makefile.am index 687aa72..74cc574 100644 --- a/plugins/dalvik/pseudo/Makefile.am +++ b/plugins/dalvik/pseudo/Makefile.am @@ -1,19 +1,14 @@ noinst_LTLIBRARIES = libdalvikpseudo.la -libdalvikpseudo_la_SOURCES = \ - fill.h fill.c \ - identifiers.h \ +libdalvikpseudo_la_SOURCES = \ + fill.h fill.c \ + identifiers.h \ switch.h switch.c -libdalvikpseudo_la_LIBADD = +libdalvikpseudo_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdalvikpseudo_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dalvik/python/Makefile.am b/plugins/dalvik/python/Makefile.am index 90c8924..74fe00d 100644 --- a/plugins/dalvik/python/Makefile.am +++ b/plugins/dalvik/python/Makefile.am @@ -1,15 +1,16 @@ noinst_LTLIBRARIES = libdalvikpython.la -libdalvikpython_la_SOURCES = \ - instruction.h instruction.c \ - module.h module.c \ +libdalvikpython_la_SOURCES = \ + instruction.h instruction.c \ + module.h module.c \ processor.h processor.c -libdalvikpython_la_LIBADD = \ +libdalvikpython_la_LIBADD = \ v35/libdalvikpythonv35.la -libdalvikpython_la_LDFLAGS = +libdalvikpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -17,9 +18,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdalvikpython_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = v35 diff --git a/plugins/dalvik/python/instruction.c b/plugins/dalvik/python/instruction.c index c9d039f..a6d4ad4 100644 --- a/plugins/dalvik/python/instruction.c +++ b/plugins/dalvik/python/instruction.c @@ -102,7 +102,10 @@ bool register_python_dalvik_instruction(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_INSTRUCTION, type, get_python_arch_instruction_type())) + if (!ensure_python_arch_instruction_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_INSTRUCTION, type)) return false; return true; diff --git a/plugins/dalvik/python/processor.c b/plugins/dalvik/python/processor.c index 26fd8b7..9885a04 100644 --- a/plugins/dalvik/python/processor.c +++ b/plugins/dalvik/python/processor.c @@ -100,7 +100,10 @@ bool register_python_dalvik_processor(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_PROCESSOR, type, get_python_arch_processor_type())) + if (!ensure_python_arch_processor_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_DALVIK_PROCESSOR, type)) return false; return true; diff --git a/plugins/dalvik/python/v35/Makefile.am b/plugins/dalvik/python/v35/Makefile.am index 3dda5c1..4464dcc 100644 --- a/plugins/dalvik/python/v35/Makefile.am +++ b/plugins/dalvik/python/v35/Makefile.am @@ -1,20 +1,15 @@ noinst_LTLIBRARIES = libdalvikpythonv35.la -libdalvikpythonv35_la_SOURCES = \ - instruction.h instruction.c \ - module.h module.c \ +libdalvikpythonv35_la_SOURCES = \ + instruction.h instruction.c \ + module.h module.c \ processor.h processor.c -libdalvikpythonv35_la_LDFLAGS = +libdalvikpythonv35_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdalvikpythonv35_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dalvik/python/v35/instruction.c b/plugins/dalvik/python/v35/instruction.c index f5ccc2c..7373e77 100644 --- a/plugins/dalvik/python/v35/instruction.c +++ b/plugins/dalvik/python/v35/instruction.c @@ -100,8 +100,9 @@ bool register_python_dalvik35_instruction(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_INSTRUCTION, - type, get_python_dalvik_instruction_type())) + /* TODO : ensure get_python_dalvik_instruction_type() */ + + if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_INSTRUCTION, type)) return false; return true; diff --git a/plugins/dalvik/python/v35/processor.c b/plugins/dalvik/python/v35/processor.c index fea342b..8df8249 100644 --- a/plugins/dalvik/python/v35/processor.c +++ b/plugins/dalvik/python/v35/processor.c @@ -100,8 +100,9 @@ bool register_python_dalvik35_processor(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_PROCESSOR, - type, get_python_dalvik_processor_type())) + /* TODO : ensure get_python_dalvik_processor_type() */ + + if (!register_class_for_pygobject(dict, G_TYPE_DALVIK35_PROCESSOR, type)) return false; return true; diff --git a/plugins/dalvik/register.c b/plugins/dalvik/register.c index 4145d27..8413108 100644 --- a/plugins/dalvik/register.c +++ b/plugins/dalvik/register.c @@ -30,7 +30,7 @@ #include <arch/register-int.h> #include <common/sort.h> -#include <gtkext/gtkblockdisplay.h> +#include <core/columns.h> @@ -70,25 +70,28 @@ static void g_dalvik_register_dispose(GDalvikRegister *); /* Procède à la libération totale de la mémoire. */ static void g_dalvik_register_finalize(GDalvikRegister *); -/* Produit une empreinte à partir d'un registre. */ -static guint g_dalvik_register_hash(const GDalvikRegister *); - -/* Traduit un registre en version humainement lisible. */ -static void g_dalvik_register_print(const GDalvikRegister *, GBufferLine *); - /* Crée une réprésentation de registre Dalvik. */ static GArchRegister *_g_dalvik_register_new(uint16_t); -/* --------------------- TRANSPOSITIONS VIA CACHE DES REGISTRES --------------------- */ +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Produit une empreinte à partir d'un registre. */ +static guint g_dalvik_register_hash(const GDalvikRegister *); +/* Compare un registre avec un autre. */ +static int g_dalvik_register_compare(const GDalvikRegister *, const GDalvikRegister *); + +/* Traduit un registre en version humainement lisible. */ +static void g_dalvik_register_print(const GDalvikRegister *, GBufferLine *); -/* Charge un registre depuis une mémoire tampon. */ -static GArchRegister *g_dalvik_register_unserialize(GDalvikRegister *, GAsmStorage *, packed_buffer *); +/* Charge un contenu depuis une mémoire tampon. */ +static bool g_dalvik_register_load(GDalvikRegister *, GObjectStorage *, packed_buffer_t *); -/* Sauvegarde un registre dans une mémoire tampon. */ -static bool g_dalvik_register_serialize(const GDalvikRegister *, GAsmStorage *, packed_buffer *); +/* Sauvegarde un contenu dans une mémoire tampon. */ +static bool g_dalvik_register_store(GDalvikRegister *, GObjectStorage *, packed_buffer_t *); @@ -130,20 +133,21 @@ G_DEFINE_TYPE(GDalvikRegister, g_dalvik_register, G_TYPE_ARCH_REGISTER); static void g_dalvik_register_class_init(GDalvikRegisterClass *klass) { GObjectClass *object; /* Autre version de la classe */ - GArchRegisterClass *reg_class; /* Classe de haut niveau */ + GArchRegisterClass *reg; /* Classe de haut niveau */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_dalvik_register_dispose; object->finalize = (GObjectFinalizeFunc)g_dalvik_register_finalize; - reg_class = G_ARCH_REGISTER_CLASS(klass); + reg = G_ARCH_REGISTER_CLASS(klass); + + reg->hash = (reg_hash_fc)g_dalvik_register_hash; + reg->compare = (reg_compare_fc)g_dalvik_register_compare; + reg->print = (reg_print_fc)g_dalvik_register_print; - reg_class->hash = (reg_hash_fc)g_dalvik_register_hash; - reg_class->compare = (reg_compare_fc)g_dalvik_register_compare; - reg_class->print = (reg_print_fc)g_dalvik_register_print; - reg_class->unserialize = (reg_unserialize_fc)g_dalvik_register_unserialize; - reg_class->serialize = (reg_serialize_fc)g_dalvik_register_serialize; + reg->load = (load_register_fc)g_dalvik_register_load; + reg->store = (store_register_fc)g_dalvik_register_store; } @@ -206,50 +210,6 @@ static void g_dalvik_register_finalize(GDalvikRegister *reg) /****************************************************************************** * * -* Paramètres : reg = opérande à consulter pour le calcul. * -* * -* Description : Produit une empreinte à partir d'un registre. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static guint g_dalvik_register_hash(const GDalvikRegister *reg) -{ - return reg->index; - -} - - -/****************************************************************************** -* * -* Paramètres : reg = registre à transcrire. * -* line = ligne tampon où imprimer l'opérande donné. * -* * -* Description : Traduit un registre en version humainement lisible. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_dalvik_register_print(const GDalvikRegister *reg, GBufferLine *line) -{ - char key[MAX_REGNAME_LEN]; /* Mot clef principal */ - size_t klen; /* Taille de ce mot clef */ - - klen = snprintf(key, MAX_REGNAME_LEN, "v%hu", reg->index); - - g_buffer_line_append_text(line, DLC_ASSEMBLY, key, klen, RTT_REGISTER, NULL); - -} - - -/****************************************************************************** -* * * Paramètres : index = indice du registre correspondant. * * * * Description : Crée une réprésentation de registre Dalvik. * @@ -315,6 +275,31 @@ uint16_t g_dalvik_register_get_index(const GDalvikRegister *reg) } + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : reg = opérande à consulter pour le calcul. * +* * +* Description : Produit une empreinte à partir d'un registre. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static guint g_dalvik_register_hash(const GDalvikRegister *reg) +{ + return reg->index; + +} + + /****************************************************************************** * * * Paramètres : a = premier opérande à consulter. * @@ -328,7 +313,7 @@ uint16_t g_dalvik_register_get_index(const GDalvikRegister *reg) * * ******************************************************************************/ -int g_dalvik_register_compare(const GDalvikRegister *a, const GDalvikRegister *b) +static int g_dalvik_register_compare(const GDalvikRegister *a, const GDalvikRegister *b) { int result; /* Bilan à retourner */ @@ -339,57 +324,56 @@ int g_dalvik_register_compare(const GDalvikRegister *a, const GDalvikRegister *b } - -/* ---------------------------------------------------------------------------------- */ -/* TRANSPOSITIONS VIA CACHE DES OPERANDES */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * -* Paramètres : reg = registre d'architecture à constituer. * -* storage = mécanisme de sauvegarde à manipuler. * -* pbuf = zone tampon à remplir. * +* Paramètres : reg = registre à transcrire. * +* line = ligne tampon où imprimer l'opérande donné. * * * -* Description : Charge un registre depuis une mémoire tampon. * +* Description : Traduit un registre en version humainement lisible. * * * -* Retour : Bilan de l'opération. * +* Retour : - * * * * Remarques : - * * * ******************************************************************************/ -static GArchRegister *g_dalvik_register_unserialize(GDalvikRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) +static void g_dalvik_register_print(const GDalvikRegister *reg, GBufferLine *line) { - GArchRegister *result; /* Instance à retourner */ - uint16_t index; /* Indice du registre */ - bool status; /* Bilan d'une extraction */ - GArchRegisterClass *parent; /* Classe parente à consulter */ + char key[MAX_REGNAME_LEN]; /* Mot clef principal */ + size_t klen; /* Taille de ce mot clef */ - status = extract_packed_buffer(pbuf, &index, sizeof(uint16_t), true); + klen = snprintf(key, MAX_REGNAME_LEN, "v%hu", reg->index); - if (status) - { - result = get_dalvik_register(index); + g_buffer_line_append_text(line, DLC_ASSEMBLY, key, klen, RTT_REGISTER, NULL); - if (result == NULL) - g_object_unref(G_OBJECT(reg)); +} - } - else - { - g_object_unref(G_OBJECT(reg)); - result = NULL; - } +/****************************************************************************** +* * +* Paramètres : reg = élément GLib à constuire. * +* storage = conservateur de données à manipuler ou NULL. * +* pbuf = zone tampon à lire. * +* * +* Description : Charge un contenu depuis une mémoire tampon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - if (result != NULL) - { - parent = G_ARCH_REGISTER_CLASS(g_dalvik_register_parent_class); +static bool g_dalvik_register_load(GDalvikRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + GArchRegisterClass *parent; /* Classe parente à consulter */ - result = parent->unserialize(result, storage, pbuf); + parent = G_ARCH_REGISTER_CLASS(g_dalvik_register_parent_class); - } + result = parent->load(G_ARCH_REGISTER(reg), storage, pbuf); + + if (result) + result = extract_packed_buffer(pbuf, ®->index, sizeof(uint16_t), true); return result; @@ -398,11 +382,11 @@ static GArchRegister *g_dalvik_register_unserialize(GDalvikRegister *reg, GAsmSt /****************************************************************************** * * -* Paramètres : reg = registre d'architecture à consulter. * -* storage = mécanisme de sauvegarde à manipuler. * +* Paramètres : reg = élément GLib à consulter. * +* storage = conservateur de données à manipuler ou NULL. * * pbuf = zone tampon à remplir. * * * -* Description : Sauvegarde un registre dans une mémoire tampon. * +* Description : Sauvegarde un contenu dans une mémoire tampon. * * * * Retour : Bilan de l'opération. * * * @@ -410,20 +394,17 @@ static GArchRegister *g_dalvik_register_unserialize(GDalvikRegister *reg, GAsmSt * * ******************************************************************************/ -static bool g_dalvik_register_serialize(const GDalvikRegister *reg, GAsmStorage *storage, packed_buffer *pbuf) +static bool g_dalvik_register_store(GDalvikRegister *reg, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ GArchRegisterClass *parent; /* Classe parente à consulter */ - result = extend_packed_buffer(pbuf, ®->index, sizeof(uint16_t), true); + parent = G_ARCH_REGISTER_CLASS(g_dalvik_register_parent_class); - if (result) - { - parent = G_ARCH_REGISTER_CLASS(g_dalvik_register_parent_class); + result = parent->store(G_ARCH_REGISTER(reg), storage, pbuf); - result = parent->serialize(G_ARCH_REGISTER(reg), storage, pbuf); - - } + if (result) + result = extend_packed_buffer(pbuf, ®->index, sizeof(uint16_t), true); return result; diff --git a/plugins/dalvik/register.h b/plugins/dalvik/register.h index 586d242..8c664a5 100644 --- a/plugins/dalvik/register.h +++ b/plugins/dalvik/register.h @@ -60,9 +60,6 @@ GArchRegister *g_dalvik_register_new(uint16_t); /* Fournit l'indice d'un registre Dalvik. */ uint16_t g_dalvik_register_get_index(const GDalvikRegister *); -/* Compare un registre avec un autre. */ -int g_dalvik_register_compare(const GDalvikRegister *, const GDalvikRegister *); - /* ------------------------ GESTION SOUS FORME DE SINGLETONS ------------------------ */ diff --git a/plugins/dalvik/v35/Makefile.am b/plugins/dalvik/v35/Makefile.am index 8a7be09..73e09a0 100644 --- a/plugins/dalvik/v35/Makefile.am +++ b/plugins/dalvik/v35/Makefile.am @@ -1,13 +1,15 @@ noinst_LTLIBRARIES = libdalvik35.la -libdalvik35_la_SOURCES = \ - core.h core.c \ - instruction.h instruction.c \ - operand.h \ +libdalvik35_la_SOURCES = \ + core.h core.c \ + instruction.h instruction.c \ + operand.h \ processor.h processor.c -libdalvik35_la_LIBADD = \ +libdalvik35_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + +libdalvik35_la_LIBADD = \ opcodes/libdalvik35opcodes.la @@ -16,9 +18,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdalvik35_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - SUBDIRS = opdefs opcodes diff --git a/plugins/dalvik/v35/opcodes/Makefile.am b/plugins/dalvik/v35/opcodes/Makefile.am index fd26224..8a766f9 100644 --- a/plugins/dalvik/v35/opcodes/Makefile.am +++ b/plugins/dalvik/v35/opcodes/Makefile.am @@ -13,7 +13,7 @@ noinst_LTLIBRARIES = libdalvik35opcodes.la libdalvik35opcodes_la_SOURCES = $(GENERATED_FILES) -libdalvik35opcodes_la_LIBADD = +libdalvik35opcodes_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) @@ -21,11 +21,6 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdalvik35opcodes_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - CLEANFILES = $(GENERATED_FILES) dist-hook: diff --git a/plugins/devdbg/Makefile.am b/plugins/devdbg/Makefile.am index a92744d..0bf81c6 100644 --- a/plugins/devdbg/Makefile.am +++ b/plugins/devdbg/Makefile.am @@ -11,9 +11,11 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs' endif -libspeed_la_SOURCES = \ +libspeed_la_SOURCES = \ speed.h speed.c +libspeed_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libspeed_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -23,8 +25,3 @@ libspeed_la_LDFLAGS = \ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libspeed_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dex/Makefile.am b/plugins/dex/Makefile.am index 8eb7bde..a587fe2 100644 --- a/plugins/dex/Makefile.am +++ b/plugins/dex/Makefile.am @@ -35,21 +35,23 @@ PYTHON3_SUBDIRS = python endif -libdex_la_SOURCES = \ - core.h core.c \ - class.h class.c \ - dex-int.h dex-int.c \ - dex_def.h \ - field.h field.c \ - format.h format.c \ - loading.h loading.c \ - method.h method.c \ - pool.h pool.c \ +libdex_la_SOURCES = \ + core.h core.c \ + class.h class.c \ + dex-int.h dex-int.c \ + dex_def.h \ + field.h field.c \ + format.h format.c \ + loading.h loading.c \ + method.h method.c \ + pool.h pool.c \ routine.h routine.c -libdex_la_LIBADD = \ +libdex_la_LIBADD = \ $(PYTHON3_LIBADD) +libdex_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libdex_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -61,8 +63,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdex_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/dex/core.c b/plugins/dex/core.c index 22ebfff..1101a89 100644 --- a/plugins/dex/core.c +++ b/plugins/dex/core.c @@ -24,18 +24,17 @@ #include "core.h" -#include <config.h> #include <core/global.h> #include <plugins/self.h> #include "format.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS result = add_format_dex_module_to_python_module(); #else result = true; diff --git a/plugins/dex/loading.h b/plugins/dex/loading.h index 5560e4e..4de6df1 100644 --- a/plugins/dex/loading.h +++ b/plugins/dex/loading.h @@ -26,9 +26,11 @@ #include <glib-object.h> +#include <stdbool.h> +#include <stdint.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> diff --git a/plugins/dex/pool.c b/plugins/dex/pool.c index 6007019..af591d3 100644 --- a/plugins/dex/pool.c +++ b/plugins/dex/pool.c @@ -26,6 +26,7 @@ #include <assert.h> #include <malloc.h> +#include <stdlib.h> #include <string.h> @@ -1181,6 +1182,10 @@ bool g_dex_pool_load_all_classes(GDexPool *pool, wgroup_id_t gid, GtkStatusStack size_t scount; /* Quantité de ces symboles */ uint32_t j; /* Boucle de parcours #2 */ size_t k; /* Boucle de parcours #3 */ + bool need_sort; /* Tri des symboles nécessaire */ + phys_t last; /* Dernière position rencontrée*/ + const mrange_t *range; /* Couverture du symbole */ + const vmpa2t *addr; /* Emplacement du symbole */ result = true; @@ -1229,8 +1234,38 @@ bool g_dex_pool_load_all_classes(GDexPool *pool, wgroup_id_t gid, GtkStatusStack result = g_dex_class_get_collect_symbols(pool->classes[j], &symbols, &scount); if (result) + { + /** + * Si le format DEX impose un ordre croissant dans les identifiants + * des méthodes d'une classe (champ method_idx de la structure + * encoded_method), cela ne conduit pas forcément à : + * - à disposer de champs code_off eux-même ordonnés ; + * - à retrouver des ordonnancements d'une classe à une autre. + * + * Un tri est donc forcé ici s'il s'avère nécessaire. + */ + + need_sort = false; + last = VMPA_NO_PHYSICAL; + + for (k = 0; k < scount && !need_sort; k++) + { + range = g_binary_symbol_get_range(symbols[k]); + addr = get_mrange_addr(range); + + need_sort = (last != VMPA_NO_PHYSICAL && last > get_phy_addr(addr)); + + last = get_phy_addr(addr); + + } + + if (need_sort) + qsort(symbols, count, sizeof(GBinSymbol *), (__compar_fn_t)g_binary_symbol_cmp); + result = g_binary_format_add_symbols(G_BIN_FORMAT(pool->format), symbols, count); + } + for (k = 0; k < scount; k++) g_object_unref(symbols[k]); diff --git a/plugins/dex/python/Makefile.am b/plugins/dex/python/Makefile.am index e91630e..b627157 100644 --- a/plugins/dex/python/Makefile.am +++ b/plugins/dex/python/Makefile.am @@ -1,26 +1,21 @@ noinst_LTLIBRARIES = libdexpython.la -libdexpython_la_SOURCES = \ - class.h class.c \ - constants.h constants.c \ - field.h field.c \ - format.h format.c \ - method.h method.c \ - module.h module.c \ - pool.h pool.c \ - routine.h routine.c \ +libdexpython_la_SOURCES = \ + class.h class.c \ + constants.h constants.c \ + field.h field.c \ + format.h format.c \ + method.h method.c \ + module.h module.c \ + pool.h pool.c \ + routine.h routine.c \ translate.h translate.c -libdexpython_la_LDFLAGS = +libdexpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdexpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dex/python/class.c b/plugins/dex/python/class.c index e344124..247197c 100644 --- a/plugins/dex/python/class.c +++ b/plugins/dex/python/class.c @@ -584,14 +584,14 @@ PyTypeObject *get_python_dex_class_type(void) bool register_python_dex_class(PyObject *module) { - PyTypeObject *py_dex_class_type; /* Type Python 'DexClass' */ + PyTypeObject *type; /* Type Python 'DexClass' */ PyObject *dict; /* Dictionnaire du module */ - py_dex_class_type = get_python_dex_class_type(); + type = get_python_dex_class_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DEX_CLASS, py_dex_class_type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DEX_CLASS, type)) return false; return true; diff --git a/plugins/dex/python/field.c b/plugins/dex/python/field.c index 1381af6..081d0af 100644 --- a/plugins/dex/python/field.c +++ b/plugins/dex/python/field.c @@ -181,14 +181,14 @@ PyTypeObject *get_python_dex_field_type(void) bool register_python_dex_field(PyObject *module) { - PyTypeObject *py_dex_field_type; /* Type Python 'DexField' */ + PyTypeObject *type; /* Type Python 'DexField' */ PyObject *dict; /* Dictionnaire du module */ - py_dex_field_type = get_python_dex_field_type(); + type = get_python_dex_field_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DEX_FIELD, py_dex_field_type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DEX_FIELD, type)) return false; return true; diff --git a/plugins/dex/python/format.c b/plugins/dex/python/format.c index fa65b25..4a8939b 100644 --- a/plugins/dex/python/format.c +++ b/plugins/dex/python/format.c @@ -281,7 +281,10 @@ bool register_python_dex_format(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DEX_FORMAT, type, get_python_executable_format_type())) + if (!ensure_python_executable_format_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_DEX_FORMAT, type)) return false; if (!define_python_dex_format_common_constants(type)) diff --git a/plugins/dex/python/method.c b/plugins/dex/python/method.c index fc56f29..ed67176 100644 --- a/plugins/dex/python/method.c +++ b/plugins/dex/python/method.c @@ -291,14 +291,14 @@ PyTypeObject *get_python_dex_method_type(void) bool register_python_dex_method(PyObject *module) { - PyTypeObject *py_dex_method_type; /* Type Python 'DexMethod' */ + PyTypeObject *type; /* Type Python 'DexMethod' */ PyObject *dict; /* Dictionnaire du module */ - py_dex_method_type = get_python_dex_method_type(); + type = get_python_dex_method_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DEX_METHOD, py_dex_method_type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DEX_METHOD, type)) return false; return true; diff --git a/plugins/dex/python/pool.c b/plugins/dex/python/pool.c index ddfc900..0c08865 100644 --- a/plugins/dex/python/pool.c +++ b/plugins/dex/python/pool.c @@ -822,7 +822,7 @@ bool register_python_dex_pool(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DEX_POOL, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DEX_POOL, type)) return false; return true; diff --git a/plugins/dex/python/routine.c b/plugins/dex/python/routine.c index 31410c7..af38263 100644 --- a/plugins/dex/python/routine.c +++ b/plugins/dex/python/routine.c @@ -165,7 +165,10 @@ bool register_python_dex_routine(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DEX_ROUTINE, type, get_python_binary_routine_type())) + if (!ensure_python_binary_routine_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_DEX_ROUTINE, type)) return false; return true; diff --git a/plugins/dexbnf/Makefile.am b/plugins/dexbnf/Makefile.am index 51598ce..222cc35 100644 --- a/plugins/dexbnf/Makefile.am +++ b/plugins/dexbnf/Makefile.am @@ -34,17 +34,19 @@ PYTHON3_SUBDIRS = python endif -libdexbnf_la_SOURCES = \ - context.h context.c \ - core.h core.c \ - demangler.h demangler.c \ - simple.h simple.c \ - shorty.h shorty.c \ +libdexbnf_la_SOURCES = \ + context.h context.c \ + core.h core.c \ + demangler.h demangler.c \ + simple.h simple.c \ + shorty.h shorty.c \ type.h type.c -libdexbnf_la_LIBADD = \ +libdexbnf_la_LIBADD = \ $(PYTHON3_LIBADD) +libdexbnf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libdexbnf_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -56,8 +58,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdexbnf_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/dexbnf/core.c b/plugins/dexbnf/core.c index 2b9408a..07e7545 100644 --- a/plugins/dexbnf/core.c +++ b/plugins/dexbnf/core.c @@ -24,18 +24,17 @@ #include "core.h" -#include <config.h> #include <core/demanglers.h> #include <plugins/self.h> #include "demangler.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -65,9 +64,9 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ - result = register_demangler_type("dex", G_TYPE_DEX_DEMANGLER); + result = register_demangler_type(G_TYPE_DEX_DEMANGLER); -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS if (result) result = add_mangling_dexbnf_module_to_python_module(); #endif diff --git a/plugins/dexbnf/demangler.c b/plugins/dexbnf/demangler.c index 503f7ce..03f24f7 100644 --- a/plugins/dexbnf/demangler.c +++ b/plugins/dexbnf/demangler.c @@ -58,6 +58,9 @@ static void g_dex_demangler_dispose(GDexDemangler *); /* Procède à la libération totale de la mémoire. */ static void g_dex_demangler_finalize(GDexDemangler *); +/* Fournit la désignation interne du décodeur de désignations. */ +static char *g_dex_demangler_get_key(const GDexDemangler *); + /* Indique le type défini pour un décodeur de désignations. */ @@ -88,6 +91,7 @@ static void g_dex_demangler_class_init(GDexDemanglerClass *klass) demangler = G_COMP_DEMANGLER_CLASS(klass); + demangler->get_key = (get_demangler_key_fc)g_dex_demangler_get_key; demangler->can_demangle = (can_be_demangled_fc)NULL; demangler->ns_sep = "."; @@ -173,3 +177,26 @@ GCompDemangler *g_dex_demangler_new(void) return G_COMP_DEMANGLER(result); } + + +/****************************************************************************** +* * +* Paramètres : demangler = décodeur à consulter. * +* * +* Description : Fournit la désignation interne du décodeur de désignations. * +* * +* Retour : Simple chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_dex_demangler_get_key(const GDexDemangler *demangler) +{ + char *result; /* Désignation à renvoyer */ + + result = strdup("dex"); + + return result; + +} diff --git a/plugins/dexbnf/python/Makefile.am b/plugins/dexbnf/python/Makefile.am index 59668eb..95a8b0c 100644 --- a/plugins/dexbnf/python/Makefile.am +++ b/plugins/dexbnf/python/Makefile.am @@ -1,19 +1,14 @@ noinst_LTLIBRARIES = libdexbnfpython.la -libdexbnfpython_la_SOURCES = \ - demangler.h demangler.c \ +libdexbnfpython_la_SOURCES = \ + demangler.h demangler.c \ module.h module.c -libdexbnfpython_la_LDFLAGS = +libdexbnfpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdexbnfpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dexbnf/python/demangler.c b/plugins/dexbnf/python/demangler.c index 3682216..8fc93e4 100644 --- a/plugins/dexbnf/python/demangler.c +++ b/plugins/dexbnf/python/demangler.c @@ -140,15 +140,17 @@ PyTypeObject *get_python_dex_demangler_type(void) bool register_python_dex_demangler(PyObject *module) { - PyTypeObject *py_dex_demangler_type; /* Type Python 'DexDemangler' */ + PyTypeObject *type; /* Type Python 'DexDemangler' */ PyObject *dict; /* Dictionnaire du module */ - py_dex_demangler_type = get_python_dex_demangler_type(); + type = get_python_dex_demangler_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DEX_DEMANGLER, - py_dex_demangler_type, get_python_compiler_demangler_type())) + if (!ensure_python_compiler_demangler_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_DEX_DEMANGLER, type)) return false; return true; diff --git a/plugins/dwarf/Makefile.am b/plugins/dwarf/Makefile.am index 5a8c9c9..c93e302 100644 --- a/plugins/dwarf/Makefile.am +++ b/plugins/dwarf/Makefile.am @@ -11,15 +11,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs' endif -libdwarf_la_SOURCES = \ - abbrev.h abbrev.c \ - checks.h checks.c \ - core.h core.c \ - def.h \ - die.h die.c \ - form.h form.c \ - format.h format.c \ - info.h info.c \ +libdwarf_la_SOURCES = \ + abbrev.h abbrev.c \ + checks.h checks.c \ + core.h core.c \ + def.h \ + die.h die.c \ + form.h form.c \ + format.h format.c \ + info.h info.c \ utils.h utils.c @@ -33,11 +33,13 @@ libdwarf_la_SOURCES = \ # info.h info.c \ # symbols.h symbols.c -libdwarf_la_LIBADD = \ - v2/libdwarfv2.la \ - v3/libdwarfv3.la \ +libdwarf_la_LIBADD = \ + v2/libdwarfv2.la \ + v3/libdwarfv3.la \ v4/libdwarfv4.la +libdwarf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libdwarf_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -49,8 +51,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdwarf_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = v2 v3 v4 diff --git a/plugins/dwarf/core.c b/plugins/dwarf/core.c index bf1e812..7b62fb9 100644 --- a/plugins/dwarf/core.c +++ b/plugins/dwarf/core.c @@ -24,14 +24,13 @@ #include "core.h" -#include <config.h> #include <plugins/self.h> #include "format.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ diff --git a/plugins/dwarf/info.h b/plugins/dwarf/info.h index a2fd961..6ce3e9a 100644 --- a/plugins/dwarf/info.h +++ b/plugins/dwarf/info.h @@ -29,6 +29,7 @@ #include <glibext/delayed.h> +#include <glibext/notifier.h> #include "format.h" diff --git a/plugins/dwarf/v2/Makefile.am b/plugins/dwarf/v2/Makefile.am index 1683ded..5664927 100644 --- a/plugins/dwarf/v2/Makefile.am +++ b/plugins/dwarf/v2/Makefile.am @@ -1,17 +1,12 @@ noinst_LTLIBRARIES = libdwarfv2.la -libdwarfv2_la_SOURCES = \ +libdwarfv2_la_SOURCES = \ checks.h checks.c -libdwarfv2_la_LDFLAGS = $(LIBGTK_LIBS) +libdwarfv2_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdwarfv2_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dwarf/v3/Makefile.am b/plugins/dwarf/v3/Makefile.am index b821d2a..2078058 100644 --- a/plugins/dwarf/v3/Makefile.am +++ b/plugins/dwarf/v3/Makefile.am @@ -1,17 +1,12 @@ noinst_LTLIBRARIES = libdwarfv3.la -libdwarfv3_la_SOURCES = \ +libdwarfv3_la_SOURCES = \ checks.h checks.c -libdwarfv3_la_LDFLAGS = $(LIBGTK_LIBS) +libdwarfv3_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdwarfv3_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/dwarf/v4/Makefile.am b/plugins/dwarf/v4/Makefile.am index e06e8f5..ef13b2c 100644 --- a/plugins/dwarf/v4/Makefile.am +++ b/plugins/dwarf/v4/Makefile.am @@ -1,17 +1,12 @@ noinst_LTLIBRARIES = libdwarfv4.la -libdwarfv4_la_SOURCES = \ +libdwarfv4_la_SOURCES = \ checks.h checks.c -libdwarfv4_la_LDFLAGS = $(LIBGTK_LIBS) +libdwarfv4_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libdwarfv4_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/elf/Makefile.am b/plugins/elf/Makefile.am index 880ae78..677cf93 100644 --- a/plugins/elf/Makefile.am +++ b/plugins/elf/Makefile.am @@ -37,23 +37,25 @@ PYTHON3_SUBDIRS = python endif -libelf_la_SOURCES = \ - core.h core.c \ - elf-int.h elf-int.c \ - elf_def.h \ - elf_def_arm.h \ - format.h format.c \ - dynamic.h dynamic.c \ - helper_arm.h helper_arm.c \ - loading.h loading.c \ - program.h program.c \ - section.h section.c \ - strings.h strings.c \ +libelf_la_SOURCES = \ + core.h core.c \ + elf-int.h elf-int.c \ + elf_def.h \ + elf_def_arm.h \ + format.h format.c \ + dynamic.h dynamic.c \ + helper_arm.h helper_arm.c \ + loading.h loading.c \ + program.h program.c \ + section.h section.c \ + strings.h strings.c \ symbols.h symbols.c -libelf_la_LIBADD = \ +libelf_la_LIBADD = \ $(PYTHON3_LIBADD) +libelf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libelf_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -65,8 +67,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libelf_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/elf/core.c b/plugins/elf/core.c index 1e98aba..bd829af 100644 --- a/plugins/elf/core.c +++ b/plugins/elf/core.c @@ -24,18 +24,17 @@ #include "core.h" -#include <config.h> #include <core/global.h> #include <plugins/self.h> #include "format.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS result = add_format_elf_module_to_python_module(); #else result = true; diff --git a/plugins/elf/loading.h b/plugins/elf/loading.h index e3016d4..270bb0b 100644 --- a/plugins/elf/loading.h +++ b/plugins/elf/loading.h @@ -26,7 +26,7 @@ #include <format/symiter.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> #include "format.h" diff --git a/plugins/elf/python/Makefile.am b/plugins/elf/python/Makefile.am index 29b7d98..1d4f671 100644 --- a/plugins/elf/python/Makefile.am +++ b/plugins/elf/python/Makefile.am @@ -1,25 +1,20 @@ noinst_LTLIBRARIES = libelfpython.la -libelfpython_la_SOURCES = \ - constants.h constants.c \ - dynamic.h dynamic.c \ - elf_def.h elf_def.c \ - format.h format.c \ - module.h module.c \ - program.h program.c \ - section.h section.c \ +libelfpython_la_SOURCES = \ + constants.h constants.c \ + dynamic.h dynamic.c \ + elf_def.h elf_def.c \ + format.h format.c \ + module.h module.c \ + program.h program.c \ + section.h section.c \ translate.h translate.c -libelfpython_la_LDFLAGS = +libelfpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libelfpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/elf/python/format.c b/plugins/elf/python/format.c index e0195c4..95eaa9a 100644 --- a/plugins/elf/python/format.c +++ b/plugins/elf/python/format.c @@ -244,18 +244,20 @@ PyTypeObject *get_python_elf_format_type(void) bool register_python_elf_format(PyObject *module) { - PyTypeObject *py_elf_format_type; /* Type Python 'ElfFormat' */ + PyTypeObject *type; /* Type Python 'ElfFormat' */ PyObject *dict; /* Dictionnaire du module */ - py_elf_format_type = get_python_elf_format_type(); + type = get_python_elf_format_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ELF_FORMAT, - py_elf_format_type, get_python_executable_format_type())) + if (!ensure_python_executable_format_is_registered()) return false; - if (!define_python_elf_format_constants(py_elf_format_type)) + if (!register_class_for_pygobject(dict, G_TYPE_ELF_FORMAT, type)) + return false; + + if (!define_python_elf_format_constants(type)) return false; return true; diff --git a/plugins/elf/strings.h b/plugins/elf/strings.h index 902c2f8..3a07b96 100644 --- a/plugins/elf/strings.h +++ b/plugins/elf/strings.h @@ -29,7 +29,7 @@ #include <glibext/delayed.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> diff --git a/plugins/elf/symbols.h b/plugins/elf/symbols.h index f4a6eec..c736d56 100644 --- a/plugins/elf/symbols.h +++ b/plugins/elf/symbols.h @@ -29,7 +29,7 @@ #include <glibext/delayed.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> diff --git a/plugins/encodings/Makefile.am b/plugins/encodings/Makefile.am new file mode 100644 index 0000000..6dd71fb --- /dev/null +++ b/plugins/encodings/Makefile.am @@ -0,0 +1,64 @@ + +lib_LTLIBRARIES = libencodings.la + +libdir = $(pluginslibdir) + + +if BUILD_PYTHON_PACKAGE + +RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs:$$ORIGIN' + +else + +RUN_PATH = -Wl,-rpath,'$$ORIGIN' + +endif + +if BUILD_PYTHON3_BINDINGS + +PYTHON3_LIBADD = python/libencodingspython.la + +if BUILD_DISCARD_LOCAL + +if BUILD_PYTHON_PACKAGE +PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN/..' +else +PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN' +endif + +else + +PYTHON3_RUN_PATH = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs + +endif + +PYTHON3_LDFLAGS = $(PYTHON3_RUN_PATH) -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so + +PYTHON3_SUBDIRS = python + +endif + + +libencodings_la_SOURCES = \ + base64.h base64.c \ + core.h core.c + +libencodings_la_LIBADD = \ + $(PYTHON3_LIBADD) \ + rost/libencodingsrost.la + +libencodings_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + +libencodings_la_LDFLAGS = \ + -avoid-version \ + -L$(top_srcdir)/src/.libs -lchrysacore \ + -L$(top_srcdir)/plugins/pe/.libs -lpe \ + $(RUN_PATH) $(PYTHON3_LDFLAGS) + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libencodings_la_SOURCES:%c=) + + +SUBDIRS = $(PYTHON3_SUBDIRS) rost diff --git a/plugins/encodings/base64.c b/plugins/encodings/base64.c new file mode 100644 index 0000000..c749a87 --- /dev/null +++ b/plugins/encodings/base64.c @@ -0,0 +1,139 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.c - calculs d'encodages en base 64 + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "base64.h" + + + +/****************************************************************************** +* * +* Paramètres : input = données d'entrée à traiter. * +* output = données sortantes constituées. [OUT] * +* alphabet = alphabet d'encodage mis à disposition. * +* * +* Description : Procède à l'encodage d'un contenu en base 64. * +* * +* Retour : Bilan de l'opération : true en cas de réussite, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool _base64_encode(const sized_binary_t *input, sized_string_t *output, const sized_string_t *alphabet) +{ + bool result; /* Bilan à retourner */ + const bin_t *src; /* Tête de lecture #1 */ + const bin_t *alpha; /* Tête de lecture #2 */ + bin_t *iter; /* Tête d'écriture */ + size_t i; /* Boucle de parcours */ + + result = (alphabet->len == 64); + if (!result) goto exit; + + /* Création du réceptacle */ + + output->len = input->len * 4 / 3; + + if (output->len % 4 != 0) + output->len += (4 - output->len % 4); + + output->data = malloc((output->len + 1) * sizeof(bin_t)); + + /* Encodage du corps du message */ + + src = input->static_bin_data; + alpha = alphabet->static_bin_data; + + iter = output->bin_data; + + if (input->len > 2) + for (i = 0; i < (input->len - 2); i += 3) + { + *iter++ = alpha[(src[i] >> 2) & 0x3f]; + + *iter++ = alpha[((src[i] & 0x03) << 4) | ((src[i + 1] & 0xf0) >> 4)]; + + *iter++ = alpha[((src[i + 1] & 0x0f) << 2) | ((src[i + 2] & 0xc0) >> 6)]; + + *iter++ = alpha[src[i + 2] & 0x3f]; + + } + else + i = 0; + + /* Bourrage final ? */ + + if (i < input->len) + { + *iter++ = alpha[(src[i] >> 2) & 0x3f]; + + if (i == (input->len - 1)) + { + *iter++ = alpha[((src[i] & 0x03) << 4)]; + *iter++ = '='; + } + else + { + *iter++ = alpha[((src[i] & 0x03) << 4) | ((src[i + 1] & 0xf0) >> 4)]; + *iter++ = alpha[((src[i + 1] & 0x0f) << 2)]; + } + + *iter++ = '='; + } + + *iter = 0x00; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : input = données d'entrée à traiter. * +* output = données sortantes constituées. [OUT] * +* * +* Description : Procède à l'encodage par défaut d'un contenu en base 64. * +* * +* Retour : Bilan de l'opération : true en cas de réussite, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool base64_encode(const sized_binary_t *input, sized_string_t *output) +{ + bool result; /* Bilan à retourner */ + + const sized_string_t alphabet = { + .static_data = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", + .len = 64 + }; + + result = _base64_encode(input, output, &alphabet); + + return result; + +} diff --git a/plugins/encodings/base64.h b/plugins/encodings/base64.h new file mode 100644 index 0000000..64ddccd --- /dev/null +++ b/plugins/encodings/base64.h @@ -0,0 +1,43 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.h - prototypes pour les calculs d'encodages en base 64 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_ENCODINGS_BASE64_H +#define _PLUGINS_ENCODINGS_BASE64_H + + +#include <stdbool.h> + + +#include <common/szstr.h> + + + +/* Procède à l'encodage d'un contenu en base 64. */ +bool _base64_encode(const sized_binary_t *, sized_string_t *, const sized_string_t *); + +/* Procède à l'encodage par défaut d'un contenu en base 64. */ +bool base64_encode(const sized_binary_t *, sized_string_t *); + + + +#endif /* _PLUGINS_ENCODINGS_BASE64_H */ diff --git a/plugins/encodings/core.c b/plugins/encodings/core.c new file mode 100644 index 0000000..2ece208 --- /dev/null +++ b/plugins/encodings/core.c @@ -0,0 +1,89 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - prototypes pour le calcul d'encodages + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "core.h" + + +#include <analysis/scan/core.h> +#include <plugins/self.h> + + +#ifdef INCLUDE_PYTHON3_BINDINGS +# include "python/module.h" +# include "python/rost/module.h" +#endif +#include "rost/base64.h" + + +#ifdef INCLUDE_PYTHON3_BINDINGS_ +# define PG_REQ RL("PyChrysalide") +#else +# define PG_REQ NO_REQ +#endif + + + +DEFINE_CHRYSALIDE_PLUGIN("Encodings", "Special encoding methods for binaries", + PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/formats"), + PG_REQ, AL(PGA_PLUGIN_INIT)); + + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* * +* Description : Prend acte du chargement du greffon. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) +{ + bool result; /* Bilan à retourner */ + GScanTokenModifier *modifier; /* Modificateur à enregistrer */ + + modifier = g_scan_base64_modifier_new(); + + result = register_scan_token_modifier(modifier); + + g_object_unref(G_OBJECT(modifier)); + + if (!result) goto exit; + +#ifdef INCLUDE_PYTHON3_BINDINGS + + result = add_encodings_module_to_python_module(); + + if (result) + result = register_encodings_rost_modifiers(); +#endif + + exit: + + return result; + +} diff --git a/plugins/encodings/core.h b/plugins/encodings/core.h new file mode 100644 index 0000000..75a6e73 --- /dev/null +++ b/plugins/encodings/core.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour le calcul d'encodages + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_ENCODINGS_CORE_H +#define _PLUGINS_ENCODINGS_CORE_H + + +#include <plugins/plugin.h> +#include <plugins/plugin-int.h> + + + +/* Prend acte du chargement du greffon. */ +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *); + + + +#endif /* _PLUGINS_ENCODINGS_CORE_H */ diff --git a/plugins/encodings/python/Makefile.am b/plugins/encodings/python/Makefile.am new file mode 100644 index 0000000..523a6f4 --- /dev/null +++ b/plugins/encodings/python/Makefile.am @@ -0,0 +1,21 @@ + +noinst_LTLIBRARIES = libencodingspython.la + +libencodingspython_la_SOURCES = \ + base64.h base64.c \ + module.h module.c + +libencodingspython_la_LIBADD = \ + rost/libencodingspythonrost.la + +libencodingspython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) \ + $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libencodingspython_la_SOURCES:%c=) + + +SUBDIRS = rost diff --git a/plugins/encodings/python/base64.c b/plugins/encodings/python/base64.c new file mode 100644 index 0000000..3bc84a2 --- /dev/null +++ b/plugins/encodings/python/base64.c @@ -0,0 +1,139 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.c - équivalent Python du fichier "plugins/encodings/base64.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "base64.h" + + +#include <pygobject.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../base64.h" + + + +/* Procède à l'encodage d'un contenu en base 64. */ +static PyObject *py_encodings_base64_encode(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = paramètre à récupérer pour le traitement. * +* * +* Description : Procède à l'encodage d'un contenu en base 64. * +* * +* Retour : None ou données sortantes constituées. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_encodings_base64_encode(PyObject *self, PyObject *args) +{ + PyObject *result; /* Valeur à retourner */ + sized_string_t alphabet; /* Alphabet de traitement ? */ + Py_ssize_t alen; /* Taille de cet alphabet */ + sized_binary_t input; /* Données à traiter */ + Py_ssize_t ilen; /* Quantité de ces données */ + int ret; /* Bilan de lecture des args. */ + sized_string_t output; /* Données encodées à exporter */ + bool status; /* Bilan de l'opération */ + +#define ENCODINGS_BASE64_ENCODE_METHOD PYTHON_METHOD_DEF \ +( \ + base64_encode, "input, /, alphabet=None", \ + METH_VARARGS, py_encodings, \ + "Encode a given content using Base64.\n" \ + "\n" \ + "The *input* argument has to be provided as bytes. The optional" \ + " *alphabet* is expected to be a 64-byte array if defined.\n" \ + "\n" \ + "The returned value is bytes or *None* in case of error." \ +) + + result = NULL; + + alphabet.data = NULL; + alen = 0; + + ret = PyArg_ParseTuple(args, "s#|s#", &input.static_data, &ilen, &alphabet.static_data, &alen); + if (!ret) goto exit; + + alphabet.len = alen; + input.len = ilen; + + if (alphabet.len > 0) + status = _base64_encode(&input, &output, &alphabet); + else + status = base64_encode(&input, &output); + + if (status) + { + result = PyBytes_FromStringAndSize(output.data, output.len); + exit_szstr(&output); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Définit une extension du module 'encodings' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_encodings_module_with_base64(PyObject *super) +{ + bool result; /* Bilan à retourner */ + + static PyMethodDef py_base64_methods[] = { + ENCODINGS_BASE64_ENCODE_METHOD, + { NULL } + }; + + result = register_python_module_methods(super, py_base64_methods); + + return result; + +} diff --git a/plugins/encodings/python/base64.h b/plugins/encodings/python/base64.h new file mode 100644 index 0000000..1e08cf6 --- /dev/null +++ b/plugins/encodings/python/base64.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.h - équivalent Python du fichier "plugins/encodings/base64.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_ENCODINGS_PYTHON_BASE64_H +#define _PLUGINS_ENCODINGS_PYTHON_BASE64_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit une extension du module 'encodings' à compléter. */ +bool populate_encodings_module_with_base64(PyObject *); + + + +#endif /* _PLUGINS_ENCODINGS_PYTHON_BASE64_H */ diff --git a/plugins/encodings/python/module.c b/plugins/encodings/python/module.c new file mode 100644 index 0000000..454159b --- /dev/null +++ b/plugins/encodings/python/module.c @@ -0,0 +1,87 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire encodings en tant que module + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "base64.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.encodings' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_encodings_module_to_python_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_ENCODINGS_DOC \ + "encodings is a module providing a few implementations" \ + " of algorithms used to encode data." + + static PyModuleDef py_chrysalide_encodings_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.encodings", + .m_doc = PYCHRYSALIDE_PLUGINS_ENCODINGS_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins"); + + module = build_python_module(super, &py_chrysalide_encodings_module); + + result = (module != NULL); + + if (result) result = populate_encodings_module_with_base64(module); + + assert(result); + + return result; + +} diff --git a/plugins/encodings/python/module.h b/plugins/encodings/python/module.h new file mode 100644 index 0000000..e7dd812 --- /dev/null +++ b/plugins/encodings/python/module.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire encodings en tant que module + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_ENCODINGS_PYTHON_MODULE_H +#define _PLUGINS_ENCODINGS_PYTHON_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.encodings' au module Python. */ +bool add_encodings_module_to_python_module(void); + + + +#endif /* _PLUGINS_ENCODINGS_PYTHON_MODULE_H */ diff --git a/plugins/encodings/python/rost/Makefile.am b/plugins/encodings/python/rost/Makefile.am new file mode 100644 index 0000000..531fb26 --- /dev/null +++ b/plugins/encodings/python/rost/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libencodingspythonrost.la + +libencodingspythonrost_la_SOURCES = \ + base64.h base64.c \ + module.h module.c + +libencodingspythonrost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) \ + $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libencodingspythonrost_la_SOURCES:%c=) diff --git a/plugins/encodings/python/rost/base64.c b/plugins/encodings/python/rost/base64.c new file mode 100644 index 0000000..57bba76 --- /dev/null +++ b/plugins/encodings/python/rost/base64.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.c - équivalent Python du fichier "plugins/encodings/rost/base64.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "base64.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/scan/patterns/modifier.h> + + +#include "../../rost/base64.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_base64_modifier, G_TYPE_SCAN_BASE64_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_base64_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_base64_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_BASE64_MODIFIER_DOC \ + "The *Base64Modifier* class transforms a byte pattern into its" \ + " base64 encoded form.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " Base64Modifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_base64_modifier_type(void) +{ + static PyMethodDef py_scan_base64_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_base64_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_base64_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.Base64Modifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_BASE64_MODIFIER_DOC, + + .tp_methods = py_scan_base64_modifier_methods, + .tp_getset = py_scan_base64_modifier_getseters, + + .tp_init = py_scan_base64_modifier_init, + .tp_new = py_scan_base64_modifier_new, + + }; + + return &py_scan_base64_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....Base64Modifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_base64_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python Base64Modifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_base64_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_BASE64_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation par encodage en Base64. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_base64_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_base64_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Base64 modifier"); + break; + + case 1: + *((GScanBase64Modifier **)dst) = G_SCAN_BASE64_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/encodings/python/rost/base64.h b/plugins/encodings/python/rost/base64.h new file mode 100644 index 0000000..0ef0834 --- /dev/null +++ b/plugins/encodings/python/rost/base64.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.h - équivalent Python du fichier "plugins/encodings/rost/base64.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H +#define _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_base64_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.Base64Modifier'. */ +bool ensure_python_scan_base64_modifier_is_registered(void); + +/* Tente de convertir en transformation par encodage en Base64. */ +int convert_to_scan_base64_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_ENCODINGS_PYTHON_ROST_BASE64_H */ diff --git a/plugins/encodings/python/rost/module.c b/plugins/encodings/python/rost/module.c new file mode 100644 index 0000000..4812bb5 --- /dev/null +++ b/plugins/encodings/python/rost/module.c @@ -0,0 +1,64 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire rost en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "base64.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les modificateurs pour ROST. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_encodings_rost_modifiers(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_base64_modifier_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/encodings/python/rost/module.h b/plugins/encodings/python/rost/module.h new file mode 100644 index 0000000..ba021cb --- /dev/null +++ b/plugins/encodings/python/rost/module.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire rost en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_ENCODINGS_PYTHON_ROST_MODULE_H +#define _PLUGINS_ENCODINGS_PYTHON_ROST_MODULE_H + + +#include <stdbool.h> + + + +/* Intègre les modificateurs pour ROST. */ +bool register_encodings_rost_modifiers(void); + + + +#endif /* _PLUGINS_ENCODINGS_PYTHON_ROST_MODULE_H */ diff --git a/plugins/encodings/rost/Makefile.am b/plugins/encodings/rost/Makefile.am new file mode 100644 index 0000000..efca690 --- /dev/null +++ b/plugins/encodings/rost/Makefile.am @@ -0,0 +1,12 @@ + +noinst_LTLIBRARIES = libencodingsrost.la + +libencodingsrost_la_SOURCES = \ + base64.h base64.c + +libencodingsrost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libencodingsrost_la_SOURCES:%c=) diff --git a/plugins/encodings/rost/base64.c b/plugins/encodings/rost/base64.c new file mode 100644 index 0000000..adbb2fb --- /dev/null +++ b/plugins/encodings/rost/base64.c @@ -0,0 +1,555 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.c - transormation en encodage Base64 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "base64.h" + + +#include <assert.h> +#include <malloc.h> +#include <stdint.h> +#include <string.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + +#include "../base64.h" + + + +/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */ + + +/* Initialise la classe des transmissions en encodage Base64. */ +static void g_scan_base64_modifier_class_init(GScanBase64ModifierClass *klass); + +/* Initialise une instance de transmission en encodage Base64. */ +static void g_scan_base64_modifier_init(GScanBase64Modifier *); + +/* Supprime toutes les références externes. */ +static void g_scan_base64_modifier_dispose(GScanBase64Modifier *); + +/* Procède à la libération totale de la mémoire. */ +static void g_scan_base64_modifier_finalize(GScanBase64Modifier *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Fournit le nom d'appel d'un modificateur pour motif. */ +static char *g_scan_base64_modifier_get_name(const GScanBase64Modifier *); + +/* Finalise l'encoddage en Base64 d'un motif transformé. */ +static void strip_base64_modifier_output(const sized_binary_t *, const sized_binary_t *, size_t, sized_binary_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_base64_modifier_transform(const GScanBase64Modifier *, const sized_binary_t *, size_t, sized_binary_t **, size_t *); + +/* Détermine si un argument est bien toléré par un modificateur. */ +static bool g_scan_base64_modifier_can_handle_arg(const GScanBase64Modifier *, const modifier_arg_t *); + +/* Transforme une séquence d'octets pour motif de recherche. */ +static bool g_scan_base64_modifier_transform_with_arg(const GScanBase64Modifier *, const sized_binary_t *, size_t, const modifier_arg_t *, sized_binary_t **, size_t *); + +/* Retrouve l'origine d'une correspondance à partir d'un indice. */ +static char *g_scan_base64_modifier_get_path(const GScanBase64Modifier *, size_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* RECHERCHE D'UN MOTIF DE TEXTE BRUT */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une transormation en encodage Base64. */ +G_DEFINE_TYPE(GScanBase64Modifier, g_scan_base64_modifier, G_TYPE_SCAN_TOKEN_MODIFIER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des transmissions en encodage Base64. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_base64_modifier_class_init(GScanBase64ModifierClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanTokenModifierClass *modifier; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_base64_modifier_dispose; + object->finalize = (GObjectFinalizeFunc)g_scan_base64_modifier_finalize; + + modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass); + + modifier->get_name = (get_scan_modifier_name_fc)g_scan_base64_modifier_get_name; + + modifier->transform = (transform_scan_token_fc)g_scan_base64_modifier_transform; + modifier->can_handle = (can_token_modifier_handle_arg)g_scan_base64_modifier_can_handle_arg; + modifier->transform_with = (transform_scan_token_with_fc)g_scan_base64_modifier_transform_with_arg; + modifier->get_path = (get_modifier_path)g_scan_base64_modifier_get_path; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance à initialiser. * +* * +* Description : Initialise une instance de transmission en encodage Base64. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_base64_modifier_init(GScanBase64Modifier *modifier) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_base64_modifier_dispose(GScanBase64Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_base64_modifier_parent_class)->dispose(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_scan_base64_modifier_finalize(GScanBase64Modifier *modifier) +{ + G_OBJECT_CLASS(g_scan_base64_modifier_parent_class)->finalize(G_OBJECT(modifier)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un modificateur livrant des encodages en Base64. * +* * +* Retour : Mécanisme mis en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanTokenModifier *g_scan_base64_modifier_new(void) +{ + GScanTokenModifier *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_SCAN_BASE64_MODIFIER, NULL); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* * +* Description : Fournit le nom d'appel d'un modificateur pour motif. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_base64_modifier_get_name(const GScanBase64Modifier *modifier) +{ + char *result; /* Désignation à retourner */ + + result = strdup("base64"); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : input = contenu brut d'origine. * +* tmpput = encodage en Base64 intermédiaire obtenu. * +* skip = nombre de caractères initiaux à sauter. * +* output = encodage en Base64 final à conserver. * +* * +* Description : Finalise l'encoddage en Base64 d'un motif transformé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void strip_base64_modifier_output(const sized_binary_t *input, const sized_binary_t *tmpput, size_t skip, sized_binary_t *output) +{ + size_t keep; /* Nombre d'octets immuables */ + + keep = (input->len * 8) / 6; + + assert(keep >= skip); + + if (skip > 0) + skip++; + + keep -= skip; + + output->len = keep; + output->bin_data = malloc(keep * sizeof(bin_t)); + + memcpy(output->bin_data, tmpput->static_bin_data + skip, keep); + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_base64_modifier_transform(const GScanBase64Modifier *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + sized_binary_t tmp_in; /* Manipulation des variations */ + sized_binary_t tmp_out; /* Manipulation des variations */ + + result = true; + + *dcount = scount * 3; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount && result; i++) + { + _src = src + i; + + tmp_in.data = malloc((_src->len + 2) * sizeof(bin_t)); + + /** + * Explications sur la définition des modifications sur les + * encodages produits : https://www.leeholmes.com/searching-for-content-in-base-64-strings/ + */ + + /* Encodage premier */ + + result = base64_encode(_src, &tmp_out); + if (!result) goto exit; + + strip_base64_modifier_output(_src, &tmp_out, 0, binary++); + + exit_szstr(&tmp_out); + + /* Variante 1 */ + + tmp_in.data[0] = ' '; + memcpy(&tmp_in.data[1], _src->static_bin_data, _src->len); + + tmp_in.len = _src->len + 1; + + result = base64_encode(&tmp_in, &tmp_out); + if (!result) goto exit; + + strip_base64_modifier_output(&tmp_in, &tmp_out, 1, binary); + + /** + * Lors qu'un unique octet est encodé, cet octet ne produit aucun + * caractère que ne dépend que de lui : + * + * | X | + * 1 2 3 4 5 6 | 7 8 1 2 3 4 | 5 6 7 8 1 2 | 3 4 5 6 7 8 + * + * Les compteurs sont alors diminués. + */ + + if (binary->len == 0) + (*dcount)--; + else + binary++; + + exit_szstr(&tmp_out); + + /* Variante 2 */ + + tmp_in.data[0] = ' '; + tmp_in.data[2] = ' '; + memcpy(&tmp_in.data[2], _src->static_bin_data, _src->len); + + tmp_in.len = _src->len + 2; + + result = base64_encode(&tmp_in, &tmp_out); + if (!result) goto exit; + + strip_base64_modifier_output(&tmp_in, &tmp_out, 2, binary++); + + exit_szstr(&tmp_out); + + exit: + + exit_szstr(&tmp_in); + + } + + if (!result) + { + for (i = 0; i < *dcount; i++) + exit_szstr(&(*dest)[i]); + + free(*dest); + + *dcount = 0; + *dest = NULL; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* arg = argument de personnalisation. * +* * +* Description : Détermine si un argument est bien toléré par un modificateur.* +* * +* Retour : Bilan de la consultation : support ou non. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_base64_modifier_can_handle_arg(const GScanBase64Modifier *modifier, const modifier_arg_t *arg) +{ + bool result; /* Bilan d'opération à renvoyer*/ + + switch (arg->type) + { + case MAT_STRING: + result = (arg->value.string.len == 64); + break; + + default: + result = false; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à solliciter. * +* src = séquences d'octets à traiter. * +* scount = quantité de ces séquences. * +* arg = argument de personnalisation. * +* dest = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] * +* dcount = quantité de ces séquences. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Bilan de l'opération : succès ou échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_scan_base64_modifier_transform_with_arg(const GScanBase64Modifier *modifier, const sized_binary_t *src, size_t scount, const modifier_arg_t *arg, sized_binary_t **dest, size_t *dcount) +{ + bool result; /* Bilan d'opération à renvoyer*/ + sized_binary_t *binary; /* Raccourci vers le stockage */ + size_t i; /* Boucle de parcours #1 */ + const sized_binary_t *_src; /* Source courante */ + sized_binary_t tmp_in; /* Manipulation des variations */ + sized_binary_t tmp_out; /* Manipulation des variations */ + + result = (arg->type == MAT_STRING); + if (!result) goto bad_arg; + + *dcount = scount * 3; + *dest = calloc(*dcount, sizeof(sized_binary_t)); + + binary = &(*dest)[0]; + + for (i = 0; i < scount && result; i++) + { + _src = src + i; + + tmp_in.data = malloc((_src->len + 2) * sizeof(bin_t)); + + /** + * Explications sur la définition des modifications sur les + * encodages produits : https://www.leeholmes.com/searching-for-content-in-base-64-strings/ + */ + + /* Encodage premier */ + + result = _base64_encode(_src, &tmp_out, &arg->value.string); + if (!result) goto exit; + + strip_base64_modifier_output(_src, &tmp_out, 0, binary++); + + exit_szstr(&tmp_out); + + /* Variante 1 */ + + tmp_in.data[0] = ' '; + memcpy(&tmp_in.data[1], _src->static_bin_data, _src->len); + + tmp_in.len = _src->len + 1; + + result = _base64_encode(&tmp_in, &tmp_out, &arg->value.string); + if (!result) goto exit; + + strip_base64_modifier_output(&tmp_in, &tmp_out, 1, binary++); + + exit_szstr(&tmp_out); + + /* Variante 2 */ + + tmp_in.data[0] = ' '; + tmp_in.data[2] = ' '; + memcpy(&tmp_in.data[2], _src->static_bin_data, _src->len); + + tmp_in.len = _src->len + 2; + + result = _base64_encode(&tmp_in, &tmp_out, &arg->value.string); + if (!result) goto exit; + + strip_base64_modifier_output(&tmp_in, &tmp_out, 2, binary++); + + exit_szstr(&tmp_out); + + exit: + + exit_szstr(&tmp_in); + + } + + if (!result) + { + for (i = 0; i < *dcount; i++) + exit_szstr(&(*dest)[i]); + + free(*dest); + + *dcount = 0; + *dest = NULL; + + } + + bad_arg: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : modifier = modificateur à consulter. * +* index = indice de la combinaison ciblée. [OUT] * +* * +* Description : Retrouve l'origine d'une correspondance à partir d'un indice.* +* * +* Retour : Version humainement lisible de la combinaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_scan_base64_modifier_get_path(const GScanBase64Modifier *modifier, size_t *index) +{ + char *result; /* Combinaison à retourner */ + + if (*index > 3) + { + result = NULL; + (*index) -= 3; + } + + else + result = strdup("base64"); + + return result; + +} diff --git a/plugins/encodings/rost/base64.h b/plugins/encodings/rost/base64.h new file mode 100644 index 0000000..646b945 --- /dev/null +++ b/plugins/encodings/rost/base64.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * base64.h - prototypes pour la transormation en encodage Base64 + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_ENCODINGS_ROST_BASE64_H +#define _PLUGINS_ENCODINGS_ROST_BASE64_H + + +#include <glib-object.h> + + +#include <analysis/scan/patterns/modifier.h> + + + +#define G_TYPE_SCAN_BASE64_MODIFIER g_scan_base64_modifier_get_type() +#define G_SCAN_BASE64_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_BASE64_MODIFIER, GScanBase64Modifier)) +#define G_IS_SCAN_BASE64_MODIFIER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_BASE64_MODIFIER)) +#define G_SCAN_BASE64_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_BASE64_MODIFIER, GScanBase64ModifierClass)) +#define G_IS_SCAN_BASE64_MODIFIER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_BASE64_MODIFIER)) +#define G_SCAN_BASE64_MODIFIER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_BASE64_MODIFIER, GScanBase64ModifierClass)) + + +/* Transormation en encodage Base64 (instance) */ +typedef GScanTokenModifier GScanBase64Modifier; + +/* Transormation en encodage Base64 (classe) */ +typedef GScanTokenModifierClass GScanBase64ModifierClass; + + +/* Indique le type défini pour une transormation en encodage Base64. */ +GType g_scan_base64_modifier_get_type(void); + +/* Construit un modificateur livrant des encodages en Base64. */ +GScanTokenModifier *g_scan_base64_modifier_new(void); + + + +#endif /* _PLUGINS_ENCODINGS_ROST_BASE64_H */ diff --git a/plugins/fmtp/Makefile.am b/plugins/fmtp/Makefile.am index f365c03..388adf3 100644 --- a/plugins/fmtp/Makefile.am +++ b/plugins/fmtp/Makefile.am @@ -11,10 +11,12 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs' endif -libfmtp_la_SOURCES = \ - def.h \ +libfmtp_la_SOURCES = \ + def.h \ parser.h parser.c +libfmtp_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libfmtp_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -24,8 +26,3 @@ libfmtp_la_LDFLAGS = \ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libfmtp_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/gdbrsp/python/gdb.c b/plugins/gdbrsp/python/gdb.c index 24d9717..15c9f94 100644 --- a/plugins/gdbrsp/python/gdb.c +++ b/plugins/gdbrsp/python/gdb.c @@ -163,7 +163,10 @@ bool ensure_python_gdb_debugger_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_GDB_DEBUGGER, type, get_python_binary_debugger_type())) + if (!ensure_python_binary_debugger_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_GDB_DEBUGGER, type)) return false; } diff --git a/plugins/itanium/Makefile.am b/plugins/itanium/Makefile.am index e1b2d9e..eee0da4 100644 --- a/plugins/itanium/Makefile.am +++ b/plugins/itanium/Makefile.am @@ -35,17 +35,19 @@ PYTHON3_SUBDIRS = python endif -libitanium_la_SOURCES = \ - abi.h abi.c \ - component-int.h \ - component.h component.c \ - context.h context.c \ - core.h core.c \ +libitanium_la_SOURCES = \ + abi.h abi.c \ + component-int.h \ + component.h component.c \ + context.h context.c \ + core.h core.c \ demangler.h demangler.c -libitanium_la_LIBADD = \ +libitanium_la_LIBADD = \ $(PYTHON3_LIBADD) +libitanium_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libitanium_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -57,8 +59,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libitanium_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/itanium/core.c b/plugins/itanium/core.c index 6bf67c1..3f3feb0 100644 --- a/plugins/itanium/core.c +++ b/plugins/itanium/core.c @@ -24,18 +24,17 @@ #include "core.h" -#include <config.h> #include <core/demanglers.h> #include <plugins/self.h> #include "demangler.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -65,9 +64,9 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ - result = register_demangler_type("itanium", G_TYPE_ITANIUM_DEMANGLER); + result = register_demangler_type(G_TYPE_ITANIUM_DEMANGLER); -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS if (result) result = add_mangling_itanium_module_to_python_module(); #endif diff --git a/plugins/itanium/demangler.c b/plugins/itanium/demangler.c index 5fe0d09..fc445f5 100644 --- a/plugins/itanium/demangler.c +++ b/plugins/itanium/demangler.c @@ -58,6 +58,9 @@ static void g_itanium_demangler_dispose(GItaniumDemangler *); /* Procède à la libération totale de la mémoire. */ static void g_itanium_demangler_finalize(GItaniumDemangler *); +/* Fournit la désignation interne du décodeur de désignations. */ +static char *g_itanium_demangler_get_key(const GItaniumDemangler *); + /* Indique le type défini pour un décodeur de désignations. */ @@ -88,6 +91,7 @@ static void g_itanium_demangler_class_init(GItaniumDemanglerClass *klass) demangler = G_COMP_DEMANGLER_CLASS(klass); + demangler->get_key = (get_demangler_key_fc)g_itanium_demangler_get_key; demangler->can_demangle = (can_be_demangled_fc)NULL; demangler->ns_sep = "::"; @@ -173,3 +177,26 @@ GCompDemangler *g_itanium_demangler_new(void) return G_COMP_DEMANGLER(result); } + + +/****************************************************************************** +* * +* Paramètres : demangler = décodeur à consulter. * +* * +* Description : Fournit la désignation interne du décodeur de désignations. * +* * +* Retour : Simple chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_itanium_demangler_get_key(const GItaniumDemangler *demangler) +{ + char *result; /* Désignation à renvoyer */ + + result = strdup("itanium"); + + return result; + +} diff --git a/plugins/itanium/python/Makefile.am b/plugins/itanium/python/Makefile.am index b0a3da1..a00bda8 100644 --- a/plugins/itanium/python/Makefile.am +++ b/plugins/itanium/python/Makefile.am @@ -1,19 +1,14 @@ noinst_LTLIBRARIES = libitaniumpython.la -libitaniumpython_la_SOURCES = \ - demangler.h demangler.c \ +libitaniumpython_la_SOURCES = \ + demangler.h demangler.c \ module.h module.c -libitaniumpython_la_LDFLAGS = +libitaniumpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libitaniumpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/itanium/python/demangler.c b/plugins/itanium/python/demangler.c index 5819ac4..12cc6c5 100644 --- a/plugins/itanium/python/demangler.c +++ b/plugins/itanium/python/demangler.c @@ -140,15 +140,17 @@ PyTypeObject *get_python_itanium_demangler_type(void) bool register_python_itanium_demangler(PyObject *module) { - PyTypeObject *py_itanium_demangler_type;/* Type 'ItaniumDemangler' */ + PyTypeObject *type; /* Type 'ItaniumDemangler' */ PyObject *dict; /* Dictionnaire du module */ - py_itanium_demangler_type = get_python_itanium_demangler_type(); + type = get_python_itanium_demangler_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ITANIUM_DEMANGLER, - py_itanium_demangler_type, get_python_compiler_demangler_type())) + if (!ensure_python_compiler_demangler_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ITANIUM_DEMANGLER, type)) return false; return true; diff --git a/plugins/java/Makefile.am b/plugins/java/Makefile.am index 0e40bfa..cd94927 100644 --- a/plugins/java/Makefile.am +++ b/plugins/java/Makefile.am @@ -16,14 +16,9 @@ libformatjava_la_SOURCES = \ # method.h method.c \ # pool.h pool.c -libformatjava_la_LDFLAGS = +libformatjava_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) devdir = $(includedir)/chrysalide/$(subdir:src/%=%) dev_HEADERS = $(libformatjava_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/javadesc/Makefile.am b/plugins/javadesc/Makefile.am index 7a79b99..8f91010 100644 --- a/plugins/javadesc/Makefile.am +++ b/plugins/javadesc/Makefile.am @@ -35,16 +35,18 @@ PYTHON3_SUBDIRS = python endif -libjavadesc_la_SOURCES = \ - context.h context.c \ - core.h core.c \ - demangler.h demangler.c \ - field.h field.c \ +libjavadesc_la_SOURCES = \ + context.h context.c \ + core.h core.c \ + demangler.h demangler.c \ + field.h field.c \ method.h method.c -libjavadesc_la_LIBADD = \ +libjavadesc_la_LIBADD = \ $(PYTHON3_LIBADD) +libjavadesc_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libjavadesc_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -56,8 +58,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libjavadesc_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/javadesc/core.c b/plugins/javadesc/core.c index bda0f56..420d9f5 100644 --- a/plugins/javadesc/core.c +++ b/plugins/javadesc/core.c @@ -24,18 +24,17 @@ #include "core.h" -#include <config.h> #include <core/demanglers.h> #include <plugins/self.h> #include "demangler.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -65,9 +64,9 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ - result = register_demangler_type("java", G_TYPE_JAVA_DEMANGLER); + result = register_demangler_type(G_TYPE_JAVA_DEMANGLER); -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS if (result) result = add_mangling_javadesc_module_to_python_module(); #endif diff --git a/plugins/javadesc/demangler.c b/plugins/javadesc/demangler.c index 78b62f1..eaacacf 100644 --- a/plugins/javadesc/demangler.c +++ b/plugins/javadesc/demangler.c @@ -58,6 +58,9 @@ static void g_java_demangler_dispose(GJavaDemangler *); /* Procède à la libération totale de la mémoire. */ static void g_java_demangler_finalize(GJavaDemangler *); +/* Fournit la désignation interne du décodeur de désignations. */ +static char *g_java_demangler_get_key(const GJavaDemangler *); + /* Indique le type défini pour un décodeur de désignations. */ @@ -88,6 +91,7 @@ static void g_java_demangler_class_init(GJavaDemanglerClass *klass) demangler = G_COMP_DEMANGLER_CLASS(klass); + demangler->get_key = (get_demangler_key_fc)g_java_demangler_get_key; demangler->can_demangle = (can_be_demangled_fc)NULL; demangler->ns_sep = "."; @@ -173,3 +177,26 @@ GCompDemangler *g_java_demangler_new(void) return G_COMP_DEMANGLER(result); } + + +/****************************************************************************** +* * +* Paramètres : demangler = décodeur à consulter. * +* * +* Description : Fournit la désignation interne du décodeur de désignations. * +* * +* Retour : Simple chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_java_demangler_get_key(const GJavaDemangler *demangler) +{ + char *result; /* Désignation à renvoyer */ + + result = strdup("java"); + + return result; + +} diff --git a/plugins/javadesc/python/Makefile.am b/plugins/javadesc/python/Makefile.am index aa7deeb..2b1a8eb 100644 --- a/plugins/javadesc/python/Makefile.am +++ b/plugins/javadesc/python/Makefile.am @@ -1,19 +1,14 @@ noinst_LTLIBRARIES = libjavadescpython.la -libjavadescpython_la_SOURCES = \ - demangler.h demangler.c \ +libjavadescpython_la_SOURCES = \ + demangler.h demangler.c \ module.h module.c -libjavadescpython_la_LDFLAGS = +libjavadescpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libjavadescpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/javadesc/python/demangler.c b/plugins/javadesc/python/demangler.c index 3a972cee..62b24c7 100644 --- a/plugins/javadesc/python/demangler.c +++ b/plugins/javadesc/python/demangler.c @@ -142,15 +142,17 @@ PyTypeObject *get_python_java_demangler_type(void) bool register_python_java_demangler(PyObject *module) { - PyTypeObject *py_java_demangler_type; /* Type Python 'JavaDemangler' */ + PyTypeObject *type; /* Type Python 'JavaDemangler' */ PyObject *dict; /* Dictionnaire du module */ - py_java_demangler_type = get_python_java_demangler_type(); + type = get_python_java_demangler_type(); dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_JAVA_DEMANGLER, - py_java_demangler_type, get_python_compiler_demangler_type())) + if (!ensure_python_compiler_demangler_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_JAVA_DEMANGLER, type)) return false; return true; diff --git a/plugins/kaitai/Makefile.am b/plugins/kaitai/Makefile.am new file mode 100644 index 0000000..9a4e112 --- /dev/null +++ b/plugins/kaitai/Makefile.am @@ -0,0 +1,93 @@ + +BUILT_SOURCES = grammar.h + + +# On évite d'utiliser les variables personnalisées de type *_la_[YL]FLAGS +# afin de conserver des noms de fichiers simples, ie sans le nom de la +# bibliothèque de sortie en préfixe. + +AM_YFLAGS = -v -d -p kaitai_ -Wno-yacc -Wcounterexamples + +AM_LFLAGS = -P kaitai_ -o lex.yy.c --header-file=tokens.h \ + -Dyyget_lineno=kaitai_get_lineno \ + -Dyy_scan_bytes=kaitai__scan_bytes \ + -Dyy_delete_buffer=kaitai__delete_buffer + +lib_LTLIBRARIES = libkaitai.la + +libdir = $(pluginslibdir) + + +if BUILD_PYTHON_PACKAGE + +RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs' + +endif + +if BUILD_PYTHON3_BINDINGS + +PYTHON3_LIBADD = python/libkaitaipython.la + +if BUILD_DISCARD_LOCAL + +if BUILD_PYTHON_PACKAGE +PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN/..' +else +PYTHON3_RUN_PATH = -Wl,-rpath,'$$ORIGIN' +endif + +else + +PYTHON3_RUN_PATH = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs + +endif + +PYTHON3_LDFLAGS = $(PYTHON3_RUN_PATH) -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so + +PYTHON3_SUBDIRS = python + +endif + + +libkaitai_la_SOURCES = \ + array-int.h \ + array.h array.c \ + core.h core.c \ + expression.h \ + import.h import.c \ + parser-int.h \ + parser.h parser.c \ + record-int.h \ + record.h record.c \ + scope.h scope.c \ + stream-int.h \ + stream.h stream.c \ + tokens.l \ + grammar.y + +libkaitai_la_LIBADD = \ + parsers/libkaitaiparsers.la \ + records/libkaitairecords.la \ + rost/libkaitairost.la \ + $(PYTHON3_LIBADD) + +libkaitai_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + +libkaitai_la_LDFLAGS = \ + -L$(top_srcdir)/src/.libs -lchrysacore \ + $(PYTHON3_LDFLAGS) + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitai_la_SOURCES:%c=) + + +# Automake fait les choses à moitié +CLEANFILES = grammar.h grammar.c grammar.output tokens.c tokens.h + +# Pareil : de tous les fichiers générés, seule la sortie de Flex saute pour les distributions ! +EXTRA_DIST = tokens.h + + +SUBDIRS = parsers records rost $(PYTHON3_SUBDIRS) diff --git a/plugins/kaitai/array-int.h b/plugins/kaitai/array-int.h new file mode 100644 index 0000000..123b16d --- /dev/null +++ b/plugins/kaitai/array-int.h @@ -0,0 +1,51 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * array-int.h - prototypes pour les données associées à un flux de données Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_ARRAY_INT_H +#define PLUGINS_KAITAI_ARRAY_INT_H + + +#include "array.h" + + + +/* Tableau rassemblant des éléments divers (instance) */ +struct _GKaitaiArray +{ + GObject parent; /* A laisser en premier */ + + resolved_value_t *items; /* Eléments du tableau */ + size_t count; /* Quantité de ces éléments */ + +}; + +/* Tableau rassemblant des éléments divers (classe) */ +struct _GKaitaiArrayClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + + +#endif /* PLUGINS_KAITAI_ARRAY_INT_H */ diff --git a/plugins/kaitai/array.c b/plugins/kaitai/array.c new file mode 100644 index 0000000..86f0856 --- /dev/null +++ b/plugins/kaitai/array.c @@ -0,0 +1,376 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * array.c - données associées à un flux de données Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "array.h" + + +#include <assert.h> +#include <limits.h> +#include <malloc.h> +#include <string.h> + + +#include "array-int.h" +#include "expression.h" + + + +/* Initialise la classe des flux de données pour Kaitai. */ +static void g_kaitai_array_class_init(GKaitaiArrayClass *); + +/* Initialise un flux de données accessibles à Kaitai. */ +static void g_kaitai_array_init(GKaitaiArray *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_array_dispose(GKaitaiArray *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_array_finalize(GKaitaiArray *); + +/* Détermine la taille de la séquence d'octets du tableau. */ +static bool g_kaitai_array_compute_bytes_length(const GKaitaiArray *, size_t *); + + + +/* Indique le type défini pour un tableau rassemblant des éléments Kaitai. */ +G_DEFINE_TYPE(GKaitaiArray, g_kaitai_array, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des tableau d'éléments Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_array_class_init(GKaitaiArrayClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_array_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_array_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : array = instance à initialiser. * +* * +* Description : Initialise un tableau rassemblant des éléments divers. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_array_init(GKaitaiArray *array) +{ + array->items = NULL; + array->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : array = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_array_dispose(GKaitaiArray *array) +{ + G_OBJECT_CLASS(g_kaitai_array_parent_class)->dispose(G_OBJECT(array)); + +} + + +/****************************************************************************** +* * +* Paramètres : array = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_array_finalize(GKaitaiArray *array) +{ + G_OBJECT_CLASS(g_kaitai_array_parent_class)->finalize(G_OBJECT(array)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Constitue une amorce de tableau pour rassembler des éléments.* +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiArray *g_kaitai_array_new(void) +{ + GKaitaiArray *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_ARRAY, NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : array = tableau Kaitai à consulter. * +* * +* Description : Dénombre le nombre d'éléments enregistrés. * +* * +* Retour : Taille du tableau manipulé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_kaitai_array_count_items(const GKaitaiArray *array) +{ + size_t result; /* Quantité à retourner */ + + result = array->count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : array = tableau Kaitai à compléter. * +* item = élément Kaitai à archiver. * +* * +* Description : Intègre un élément supplémentaire dans un tableau Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_kaitai_array_append_item(GKaitaiArray *array, const resolved_value_t *item) +{ + array->items = realloc(array->items, ++array->count * sizeof(resolved_value_t)); + + COPY_RESOLVED_VALUE(array->items[array->count - 1], *item); + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de correspondances attribut/binaire. * +* index = indice de la correspondance visée. * +* item = élément archivé dans le talbeau à fournir. [OUT] * +* * +* Description : Fournit un élément ciblé dans un tableau Kaitai. * +* * +* Retour : Validité de l'emplacmeent pour élément à renseigner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_array_get_item(const GKaitaiArray *array, size_t index, resolved_value_t *item) +{ + bool result; /* Bilan à retourner */ + + result = (index < array->count); + + if (result) + COPY_RESOLVED_VALUE(*item, array->items[index]); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : array = tableau Kaitai à consulter. * +* length = nombre d'octets représentés. [OUT] * +* * +* Description : Détermine la taille de la séquence d'octets du tableau. * +* * +* Retour : true si le tableau peut être converti en octets, ou false. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_array_compute_bytes_length(const GKaitaiArray *array, size_t *length) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + const resolved_value_t *item; /* Elément en cours d'analyse */ + size_t extra; /* Taille d'un sous-tableau */ + + result = true; + + *length = 0; + + for (i = 0; i < array->count && result; i++) + { + item = &array->items[i]; + + switch (item->type) + { + case GVT_UNSIGNED_INTEGER: + result = (item->unsigned_integer <= UCHAR_MAX); + if (result) (*length)++; + break; + + case GVT_SIGNED_INTEGER: + result = (0 <= item->signed_integer && item->signed_integer <= SCHAR_MAX); + if (result) (*length)++; + break; + + case GVT_BYTES: + *length += item->bytes.len; + break; + + case GVT_ARRAY: + result = g_kaitai_array_compute_bytes_length(item->array, &extra); + if (result) *length += extra; + break; + + default: + result = false; + break; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : array = tableau Kaitai à consulter. * +* bytes = conversion en série d'octets équivalent. [OUT] * +* * +* Description : Convertit un tableau d'éléments en séquence d'octets. * +* * +* Retour : true si une série d'octets a pu être constituée, ou false. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_array_convert_to_bytes(const GKaitaiArray *array, sized_string_t *bytes) +{ + bool result; /* Bilan à retourner */ + size_t length; /* Taille de la chaîne finale */ + size_t i; /* Boucle de parcours */ + const resolved_value_t *item; /* Elément en cours d'analyse */ + char *iter; /* Tête d'écriture */ + sized_string_t extra; /* Données d'un sous-tableau */ + + /* Détermination de la taille finale */ + + result = g_kaitai_array_compute_bytes_length(array, &length); + + /* Construction d'une chaîne d'octets si possible */ + + if (result) + { + bytes->data = malloc(length * sizeof(char)); + bytes->len = length; + + iter = bytes->data; + + for (i = 0; i < array->count; i++) + { + item = &array->items[i]; + + switch (item->type) + { + case GVT_UNSIGNED_INTEGER: + *iter = item->unsigned_integer; + iter++; + break; + + case GVT_SIGNED_INTEGER: + *iter = item->signed_integer; + iter++; + break; + + case GVT_BYTES: + memcpy(iter, item->bytes.data, item->bytes.len); + iter += item->bytes.len; + break; + + case GVT_ARRAY: + result = g_kaitai_array_convert_to_bytes(item->array, &extra); + assert(result); + + memcpy(iter, extra.data, extra.len); + iter += extra.len; + + exit_szstr(&extra); + break; + + default: + break; + + } + + } + + } + + return result; + +} diff --git a/plugins/kaitai/array.h b/plugins/kaitai/array.h new file mode 100644 index 0000000..e93c7c0 --- /dev/null +++ b/plugins/kaitai/array.h @@ -0,0 +1,76 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * array.h - prototypes pour les données associées à un flux de données Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_ARRAY_H +#define PLUGINS_KAITAI_ARRAY_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include <common/szstr.h> + + + +/* expression.h : informations transportées par une expression */ +typedef struct _resolved_value_t resolved_value_t; + + + +#define G_TYPE_KAITAI_ARRAY g_kaitai_array_get_type() +#define G_KAITAI_ARRAY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ARRAY, GKaitaiArray)) +#define G_IS_KAITAI_ARRAY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ARRAY)) +#define G_KAITAI_ARRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ARRAY, GKaitaiArrayClass)) +#define G_IS_KAITAI_ARRAY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ARRAY)) +#define G_KAITAI_ARRAY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ARRAY, GKaitaiArrayClass)) + + +/* Tableau rassemblant des éléments divers (instance) */ +typedef struct _GKaitaiArray GKaitaiArray; + +/* Tableau rassemblant des éléments divers (classe) */ +typedef struct _GKaitaiArrayClass GKaitaiArrayClass; + + +/* Indique le type défini pour un tableau rassemblant des éléments Kaitai. */ +GType g_kaitai_array_get_type(void); + +/* Constitue une amorce de tableau pour rassembler des éléments. */ +GKaitaiArray *g_kaitai_array_new(void); + +/* Dénombre le nombre d'éléments enregistrés. */ +size_t g_kaitai_array_count_items(const GKaitaiArray *); + +/* Intègre un élément supplémentaire dans un tableau Kaitai. */ +void g_kaitai_array_append_item(GKaitaiArray *, const resolved_value_t *); + +/* Fournit un élément ciblé dans un tableau Kaitai. */ +bool g_kaitai_array_get_item(const GKaitaiArray *, size_t, resolved_value_t *); + +/* Convertit un tableau d'éléments en séquence d'octets. */ +bool g_kaitai_array_convert_to_bytes(const GKaitaiArray *, sized_string_t *); + + + +#endif /* PLUGINS_KAITAI_ARRAY_H */ diff --git a/plugins/kaitai/core.c b/plugins/kaitai/core.c new file mode 100644 index 0000000..c41d96d --- /dev/null +++ b/plugins/kaitai/core.c @@ -0,0 +1,81 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - prise en charge des descriptions de binaires au format Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "core.h" + + +#include <plugins/self.h> + + +#ifdef INCLUDE_PYTHON3_BINDINGS +# include "python/module.h" +#endif +#include "rost/core.h" + + + +#ifdef INCLUDE_PYTHON3_BINDINGS +# define PG_REQ RL("PyChrysalide") +#else +# define PG_REQ NO_REQ +#endif + + + +DEFINE_CHRYSALIDE_PLUGIN("Kaitai", "Content parser using Kaitai structure definitions", + PACKAGE_VERSION, CHRYSALIDE_WEBSITE("doc/kaitai"), + PG_REQ, AL(PGA_PLUGIN_INIT)); + + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * +* * +* Description : Prend acte du chargement du greffon. * +* * +* Retour : Bilan du chargement mené. * +* * +* Remarques : - * +* * +******************************************************************************/ + +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) +{ + bool result; /* Bilan à retourner */ + + result = add_kaitai_support_to_rost(); + +#ifdef INCLUDE_PYTHON3_BINDINGS + + if (result) + result = add_kaitai_module_to_python_module(); + + if (result) + result = populate_kaitai_module(); + +#endif + + return result; + +} diff --git a/plugins/kaitai/core.h b/plugins/kaitai/core.h new file mode 100644 index 0000000..61241f4 --- /dev/null +++ b/plugins/kaitai/core.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour la prise en charge des descriptions de binaires au format Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_CORE_H +#define _PLUGINS_KAITAI_CORE_H + + +#include <plugins/plugin.h> +#include <plugins/plugin-int.h> + + + +/* Prend acte du chargement du greffon. */ +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *); + + + +#endif /* _PLUGINS_KAITAI_CORE_H */ diff --git a/plugins/kaitai/expression.h b/plugins/kaitai/expression.h new file mode 100644 index 0000000..06cf9cf --- /dev/null +++ b/plugins/kaitai/expression.h @@ -0,0 +1,134 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expression.h - déclarations de prototypes utiles aux résolutions d'expressions + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_EXPRESSION_H +#define _PLUGINS_KAITAI_EXPRESSION_H + + +#include <stdbool.h> +#include <sys/types.h> + + +#include <common/szstr.h> + + +#include "array.h" +#include "scope.h" +#include "stream.h" + + + +/* Type de valeur résolue */ +typedef enum _GrammarValueType +{ + GVT_ERROR, /* Erreur remontée */ + GVT_UNSIGNED_INTEGER, /* Valeur entière #1 */ + GVT_SIGNED_INTEGER, /* Valeur entière #2 */ + GVT_FLOAT, /* Valeur fractionnée */ + GVT_BOOLEAN, /* Valeur booléenne */ + GVT_BYTES, /* Série d'octets dynamique */ + GVT_ARRAY, /* Tableau d'éléments divers */ + GVT_RECORD, /* Correspondance en place */ + GVT_STREAM, /* Flux de données */ + +} GrammarValueType; + +/* Informations transportées par une expression */ +typedef struct _resolved_value_t +{ + GrammarValueType type; /* Type de valeur portée */ + + union + { + unsigned long long unsigned_integer;/* Valeur entière #1 */ + signed long long signed_integer; /* Valeur entière #2 */ + double floating_number; /* Valeur à virgule flottante */ + bool status; /* Valeur à deux états */ + sized_string_t bytes; /* Série d'octets */ + + GKaitaiArray *array; /* Tableau d'éléments divers */ + GMatchRecord *record; /* Correspondance désignée */ + GKaitaiStream *stream; /* Flux de données pour Kaitai */ + + }; + +} resolved_value_t; + + +#define COPY_RESOLVED_VALUE(dst, src) \ + do \ + { \ + (dst) = (src); \ + switch ((dst).type) \ + { \ + case GVT_ARRAY: \ + g_object_ref(G_OBJECT((dst).array)); \ + break; \ + case GVT_RECORD: \ + g_object_ref(G_OBJECT((dst).record)); \ + break; \ + case GVT_STREAM: \ + g_object_ref(G_OBJECT((dst).stream)); \ + break; \ + default: \ + break; \ + } \ + } \ + while (0) + + +#define EXIT_RESOLVED_VALUE(v) \ + switch ((v).type) \ + { \ + case GVT_ARRAY: \ + g_clear_object(&(v).array); \ + break; \ + case GVT_RECORD: \ + g_clear_object(&(v).record); \ + break; \ + case GVT_STREAM: \ + g_clear_object(&(v).stream); \ + break; \ + default: \ + break; \ + } + + +/* Interprète une expression en une valeur quelconque. */ +bool resolve_kaitai_expression_as_any(const kaitai_scope_t *, const char *, size_t, resolved_value_t *); + +/* Interprète une expression en valeur ciblée entière. */ +bool resolve_kaitai_expression_as_integer(const kaitai_scope_t *, const char *, size_t, resolved_value_t *); + +/* Interprète une expression en valeur ciblée booléenne. */ +bool resolve_kaitai_expression_as_boolean(const kaitai_scope_t *, const char *, size_t, resolved_value_t *); + +/* Interprète une expression en série d'octets. */ +bool resolve_kaitai_expression_as_bytes(const kaitai_scope_t *, const char *, size_t, resolved_value_t *); + +/* Interprète une expression en flux de données pour Kaitai. */ +bool resolve_kaitai_expression_as_stream(const kaitai_scope_t *, const char *, size_t, GKaitaiStream **); + + + +#endif /* _PLUGINS_KAITAI_EXPRESSION_H */ diff --git a/plugins/kaitai/grammar.y b/plugins/kaitai/grammar.y new file mode 100644 index 0000000..9745dc8 --- /dev/null +++ b/plugins/kaitai/grammar.y @@ -0,0 +1,1919 @@ + +%{ + +#include "expression.h" +#include "tokens.h" + + +/* Affiche un message d'erreur suite à l'analyse en échec. */ +static int yyerror(yyscan_t, const kaitai_scope_t *, resolved_value_t *, const char *); + +/* Interprète une expression en une valeur quelconque. */ +static bool _resolve_kaitai_expression_as_any(const kaitai_scope_t *, const char *, size_t, resolved_value_t *); + +/* Traduit les éventuels champs impliqués dans une expression. */ +static bool reduce_resolved_kaitai_expression(resolved_value_t *); + + +%} + + +%code requires { + +#define YY_TYPEDEF_YY_SCANNER_T +typedef void *yyscan_t; + +#include <assert.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <glib.h> + +#include "expression.h" +#include "record.h" +#include "records/bits.h" +#include "records/delayed.h" +#include "records/item.h" +#include "records/list.h" + +} + +%union { + + resolved_value_t value; /* Valeur portée */ + + unsigned long long unsigned_integer; /* Valeur entière #1 */ + signed long long signed_integer; /* Valeur entière #2 */ + double floating_number; /* Valeur à virgule flottante */ + sized_string_t sized_cstring; /* Chaîne de caractères */ + char byte; /* Octet unique */ + +} + + +/** + * Cf. + * http://stackoverflow.com/questions/34418381/how-to-reference-lex-or-parse-parameters-in-flex-rules/34420950 + */ + +%define api.pure full + +%parse-param { yyscan_t yyscanner } { const kaitai_scope_t *locals } { resolved_value_t *resolved } +%lex-param { yyscan_t yyscanner } + +%code provides { + +#define YY_DECL \ + int kaitai_lex(YYSTYPE *yylval_param, yyscan_t yyscanner) + +YY_DECL; + + + +#define SET_ERR(out) \ + out.type = GVT_ERROR + +#define EXIT_WITH_ERR(out, lbl) \ + do \ + { \ + SET_ERR(out); \ + goto exit_ ## lbl; \ + } \ + while (0) + +#define CHECK_TYPE(arg, tp, out, lbl) \ + if (arg.type != tp) EXIT_WITH_ERR(out, lbl) + +#define CHECK_TYPES(arg, tp1, tp2, out, lbl) \ + if (arg.type != tp1 && arg.type != tp2) EXIT_WITH_ERR(out, lbl) + +#define REDUCE_EXPR(arg, out, lbl) \ + if (!reduce_resolved_kaitai_expression(&arg)) \ + EXIT_WITH_ERR(out, lbl) + +#define REDUCE_NUMERIC_EXPR(arg, out, lbl) \ + if (!reduce_resolved_kaitai_expression(&arg)) \ + EXIT_WITH_ERR(out, lbl); \ + if (arg.type == GVT_SIGNED_INTEGER && arg.signed_integer >= 0) \ + { \ + arg.unsigned_integer = arg.signed_integer; \ + arg.type = GVT_UNSIGNED_INTEGER; \ + } + + +#define ARITHMETIC_ADD_CODE(op1, op2, out, lbl) \ + switch (op1.type) \ + { \ + case GVT_UNSIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.unsigned_integer = op1.unsigned_integer + op2.unsigned_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + if (op1.unsigned_integer < -op2.signed_integer) \ + { \ + out.signed_integer = op1.unsigned_integer + op2.signed_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else \ + { \ + out.unsigned_integer = op1.unsigned_integer + op2.signed_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.unsigned_integer + op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_SIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + if (-op1.signed_integer > op2.unsigned_integer) \ + { \ + out.signed_integer = op1.signed_integer + op2.unsigned_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else \ + { \ + out.unsigned_integer = op1.signed_integer + op2.unsigned_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.signed_integer = op1.signed_integer + op2.signed_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.signed_integer + op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_FLOAT: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.floating_number = op1.floating_number + op2.unsigned_integer; \ + out.type = GVT_FLOAT; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.floating_number = op1.floating_number + op2.signed_integer; \ + out.type = GVT_FLOAT; \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.floating_number + op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + default: \ + EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + } + + +#define ARITHMETIC_SUB_CODE(op1, op2, out, lbl) \ + switch (op1.type) \ + { \ + case GVT_UNSIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + if (op1.unsigned_integer < op2.unsigned_integer) \ + { \ + out.signed_integer = op1.unsigned_integer - op2.unsigned_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else \ + { \ + out.unsigned_integer = op1.unsigned_integer - op2.unsigned_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.unsigned_integer = op1.unsigned_integer - op2.signed_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.unsigned_integer - op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_SIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.signed_integer = op1.signed_integer - op2.unsigned_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + if (op1.signed_integer < op2.signed_integer) \ + { \ + out.signed_integer = op1.signed_integer - op2.signed_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else \ + { \ + out.unsigned_integer = op1.signed_integer - op2.signed_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.signed_integer - op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_FLOAT: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.floating_number = op1.floating_number - op2.unsigned_integer; \ + out.type = GVT_FLOAT; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.floating_number = op1.floating_number - op2.signed_integer; \ + out.type = GVT_FLOAT; \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.floating_number - op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + default: \ + EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + } + + +#define ARITHMETIC_GENOP_CODE(op1, op2, _meth_, out, lbl) \ + switch (op1.type) \ + { \ + case GVT_UNSIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.unsigned_integer = op1.unsigned_integer _meth_ op2.unsigned_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.signed_integer = op1.unsigned_integer _meth_ op2.signed_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.unsigned_integer _meth_ op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_SIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.unsigned_integer = op1.signed_integer _meth_ op2.unsigned_integer; \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.unsigned_integer = op1.signed_integer _meth_ op2.signed_integer; \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.signed_integer _meth_ op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_FLOAT: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.unsigned_integer = op1.floating_number _meth_ op2.unsigned_integer; \ + out.type = GVT_FLOAT; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.signed_integer = op1.floating_number _meth_ op2.signed_integer; \ + out.type = GVT_FLOAT; \ + } \ + else if (op2.type == GVT_FLOAT) \ + { \ + out.floating_number = op1.floating_number _meth_ op2.floating_number; \ + out.type = GVT_FLOAT; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + default: \ + EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + } + + +/** + * Cf. https://stackoverflow.com/questions/11720656/modulo-operation-with-negative-numbers/52529440#52529440 + */ +#define EUCLIDEAN_MODULO(a, b, r) \ + r = a % (signed long long)b; \ + if (r < 0) \ + r = (b < 0) ? r - b : r + b; \ + + +#define ARITHMETIC_MOD_CODE(op1, op2, out, lbl) \ + switch (op1.type) \ + { \ + case GVT_UNSIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + EUCLIDEAN_MODULO(op1.unsigned_integer, op2.unsigned_integer, out.unsigned_integer); \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + EUCLIDEAN_MODULO(op1.unsigned_integer, op2.signed_integer, out.signed_integer); \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_SIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + EUCLIDEAN_MODULO(op1.signed_integer, op2.unsigned_integer, out.signed_integer); \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + EUCLIDEAN_MODULO(op1.signed_integer, op2.signed_integer, out.signed_integer); \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + default: \ + EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + } + + +#define RELATIONAL_CODE(op1, op2, _meth_, out, lbl) \ + switch (op1.type) \ + { \ + case GVT_UNSIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.status = (op1.unsigned_integer _meth_ op2.unsigned_integer); \ + out.type = GVT_BOOLEAN; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.status = (op1.unsigned_integer _meth_ op2.signed_integer); \ + out.type = GVT_BOOLEAN; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_SIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.status = (op1.signed_integer _meth_ op2.unsigned_integer); \ + out.type = GVT_BOOLEAN; \ + } \ + else if (op2.type == GVT_SIGNED_INTEGER) \ + { \ + out.status = (op1.signed_integer _meth_ op2.signed_integer); \ + out.type = GVT_BOOLEAN; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_BYTES: \ + if (op2.type == GVT_BYTES) \ + { \ + int __ret; \ + __ret = szmemcmp(&op1.bytes, &op2.bytes); \ + out.status = (__ret _meth_ 0); \ + out.type = GVT_BOOLEAN; \ + } \ + else if (op2.type == GVT_ARRAY) \ + { \ + sized_string_t __abytes_2; \ + int __ret; \ + if (!g_kaitai_array_convert_to_bytes(op2.array, &__abytes_2)) \ + EXIT_WITH_ERR(out, lbl); \ + __ret = szmemcmp(&op1.bytes, &__abytes_2); \ + exit_szstr(&__abytes_2); \ + out.status = (__ret _meth_ 0); \ + out.type = GVT_BOOLEAN; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_ARRAY: \ + if (op2.type == GVT_BYTES) \ + { \ + sized_string_t __abytes_1; \ + int __ret; \ + if (!g_kaitai_array_convert_to_bytes(op1.array, &__abytes_1)) \ + EXIT_WITH_ERR(out, lbl); \ + __ret = szmemcmp(&__abytes_1, &op2.bytes); \ + exit_szstr(&__abytes_1); \ + out.status = (__ret _meth_ 0); \ + out.type = GVT_BOOLEAN; \ + } \ + else if (op2.type == GVT_ARRAY) \ + { \ + sized_string_t __abytes_1; \ + sized_string_t __abytes_2; \ + int __ret; \ + if (!g_kaitai_array_convert_to_bytes(op1.array, &__abytes_1)) \ + EXIT_WITH_ERR(out, lbl); \ + if (!g_kaitai_array_convert_to_bytes(op2.array, &__abytes_2)) \ + { \ + exit_szstr(&__abytes_1); \ + EXIT_WITH_ERR(out, lbl); \ + } \ + __ret = szmemcmp(&__abytes_1, &__abytes_2); \ + exit_szstr(&__abytes_1); \ + exit_szstr(&__abytes_2); \ + out.status = (__ret _meth_ 0); \ + out.type = GVT_BOOLEAN; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_STREAM: \ + if (op2.type == GVT_STREAM) \ + { \ + GBinContent *__cnt_1; \ + GBinContent *__cnt_2; \ + __cnt_1 = g_kaitai_stream_get_content(op1.stream); \ + __cnt_2 = g_kaitai_stream_get_content(op2.stream); \ + out.status = (__cnt_1 _meth_ __cnt_2); \ + out.type = GVT_BOOLEAN; \ + g_object_unref(G_OBJECT(__cnt_1)); \ + g_object_unref(G_OBJECT(__cnt_2)); \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + default: \ + EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + } + + +#define BITWISE_CODE(op1, op2, _meth_, out, lbl) \ + switch (op1.type) \ + { \ + case GVT_UNSIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.unsigned_integer = (op1.unsigned_integer _meth_ op2.unsigned_integer); \ + out.type = GVT_UNSIGNED_INTEGER; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + case GVT_SIGNED_INTEGER: \ + if (op2.type == GVT_UNSIGNED_INTEGER) \ + { \ + out.signed_integer = (op1.signed_integer _meth_ op2.unsigned_integer); \ + out.type = GVT_SIGNED_INTEGER; \ + } \ + else EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + default: \ + EXIT_WITH_ERR(out, lbl); \ + break; \ + \ + } + + + + +} + + +%token <unsigned_integer> UNSIGNED_INTEGER +%token <signed_integer> SIGNED_INTEGER +%token <floating_number> FLOAT + +%token <sized_cstring> IDENTIFIER +%token <sized_cstring> RAW_BYTES +%token <byte> RAW_BYTE +%token <sized_cstring> RAW_BYTES_WITH_ENDING_DOT +%token <sized_cstring> PLAIN_BYTES + +%token <sized_cstring> ENCODING_NAME + + +%token PLUS "+" +%token MINUS "-" +%token MUL "*" +%token DIV "/" +%token MOD "%" + +%token LT "<" +%token LE "<=" +%token EQ "==" +%token NE "!=" +%token GT ">" +%token GE ">=" + +%token SHIFT_LEFT "<<" +%token SHIFT_RIGHT ">>" +%token BIT_AND "&" +%token BIT_OR "|" +%token BIT_XOR "^" + +%token NOT "not" +%token AND "and" +%token OR "or" + +%token PAREN_O "(" +%token PAREN_C ")" +%token HOOK_O "[" +%token HOOK_C "]" +%token COMMA "," +%token DOT "." + +%token QMARK "?" +%token COLON ":" +%token DOUBLE_COLON "::" + +%token METH_SIZE ".size" +%token METH_LENGTH ".length" +%token METH_REVERSE ".reverse" +%token METH_SUBSTRING ".substring" +%token METH_TO_I ".to_i" +%token METH_TO_I_RAD ".to_i(" +%token METH_TO_S ".to_s" +%token METH_TO_S_ENC ".to_s(" + +%token ROOT "_root" +%token PARENT "_parent" +%token LAST "_" +%token IO "_io" +%token METH_IO "._io" +%token IO_EOF ".eof" + +%token TRUE_CONST "true" +%token FALSE_CONST "false" + + + //%type <value> operand +%type <value> any_expr + //%type <value> arithm_expr + //%type <value> arithm_op + +%type <value> boolean + + + +%type <value> arithmetic_expr +%type <value> relational_expr +%type <value> logical_expr +%type <value> bitwise_expr +%type <value> ternary_expr + +%type <value> convert_2_bytes +%type <value> convert_2_integer + + +%type <value> integer + +%type <value> float + +%type <value> bytes + +%type <value> bytes_concat +%type <value> raw_bytes + + +%type <value> array +%type <value> array_items + + +%type <value> field +%type <value> enumeration +%type <value> stream +%type <value> stream_meths + + + +%destructor { printf("----------------------freeing %p...\n", &$$), fflush(NULL); } <*> + + + //%type <integer> INTEGER + // + + //%type <integer> arithm_expr + //%type <integer> arithm_op + + //%type <boolean> bool_expr + //%type <boolean> relational_op logical_op ternary_op + + + //%type <integer> constant + + + + + +/** + * Cf. https://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B#Operator_precedence + */ + + + + + +%left "?" ":" + +%left OR +%left "and" + +/* 13 */ +%left "|" + +/* 12 */ +%left "^" + +/* 11 */ +%left "&" + +%left LT LE EQ NE GT GE + +/* 7 */ +%left "<<" ">>" + + +%right NOT + +%left PLUS MINUS +%left "*" +%left DIV MOD + + +%left "[" + + + + +%left ".size" +%left ".length" +%left ".reverse" +%left ".substring" +%left ".to_i" +%left ".to_i(" +%left ".to_s" +%left ".to_s(" + +%left "._io" + +%left "." + +/* 1 */ +%right "::" + + +%% + + expressions : any_expr { *resolved = $1; } + ; + + any_expr : boolean { $$ = $1; } + | bytes { $$ = $1; } + | integer { $$ = $1; } + | float { $$ = $1; } + | array { $$ = $1; } + | field { $$ = $1; } + | enumeration { $$ = $1; } + | stream { $$ = $1; } + | stream_meths { $$ = $1; } + | arithmetic_expr { $$ = $1; } + | relational_expr { $$ = $1; } + | logical_expr { $$ = $1; } + | bitwise_expr { $$ = $1; } + | ternary_expr { $$ = $1; } + | convert_2_bytes { $$ = $1; } + | convert_2_integer { $$ = $1; } + | "(" any_expr ")" { $$ = $2; } + ; + + +/* Expressions impliquants formules et opérandes */ + + arithmetic_expr : any_expr "+" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_plus); + REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_plus); + + if ($1.type == GVT_BYTES && $3.type == GVT_BYTES) + { + $$.bytes.len = $1.bytes.len + $3.bytes.len; + $$.bytes.data = malloc($$.bytes.len); + + memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len); + memcpy($$.bytes.data + $1.bytes.len, $3.bytes.data, $3.bytes.len); + + $$.type = GVT_BYTES; + + } + + else if ($1.type == GVT_BYTES && $3.type == GVT_ARRAY) + { + sized_string_t __abytes_2; + + if (!g_kaitai_array_convert_to_bytes($3.array, &__abytes_2)) + EXIT_WITH_ERR($$, arithmetic_expr_plus); + + $$.bytes.len = $1.bytes.len + __abytes_2.len; + $$.bytes.data = malloc($$.bytes.len); + + memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len); + memcpy($$.bytes.data + $1.bytes.len, __abytes_2.data, __abytes_2.len); + + $$.type = GVT_BYTES; + + exit_szstr(&__abytes_2); + + } + + else + { + ARITHMETIC_ADD_CODE($1, $3, $$, arithmetic_expr_plus); + } + + exit_arithmetic_expr_plus: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "-" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_minus); + REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_minus); + ARITHMETIC_SUB_CODE($1, $3, $$, arithmetic_expr_minus); + exit_arithmetic_expr_minus: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "*" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_mul); + REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_mul); + ARITHMETIC_GENOP_CODE($1, $3, *, $$, arithmetic_expr_mul); + exit_arithmetic_expr_mul: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "/" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_div); + REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_div); + ARITHMETIC_GENOP_CODE($1, $3, /, $$, arithmetic_expr_div); + exit_arithmetic_expr_div: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "%" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, arithmetic_expr_mod); + REDUCE_NUMERIC_EXPR($3, $$, arithmetic_expr_mod); + ARITHMETIC_MOD_CODE($1, $3, $$, arithmetic_expr_mod); + exit_arithmetic_expr_mod: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + ; + + + relational_expr : any_expr "<" any_expr + { + REDUCE_EXPR($1, $$, relational_expr_lt); + REDUCE_EXPR($3, $$, relational_expr_lt); + RELATIONAL_CODE($1, $3, <, $$, relational_expr_lt); + exit_relational_expr_lt: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "<=" any_expr + { + REDUCE_EXPR($1, $$, relational_expr_le); + REDUCE_EXPR($3, $$, relational_expr_le); + RELATIONAL_CODE($1, $3, <=, $$, relational_expr_le); + exit_relational_expr_le: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "==" any_expr + { + REDUCE_EXPR($1, $$, relational_expr_eq); + REDUCE_EXPR($3, $$, relational_expr_eq); + RELATIONAL_CODE($1, $3, ==, $$, relational_expr_eq); + exit_relational_expr_eq: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "!=" any_expr + { + REDUCE_EXPR($1, $$, relational_expr_ne); + REDUCE_EXPR($3, $$, relational_expr_ne); + RELATIONAL_CODE($1, $3, !=, $$, relational_expr_ne); + exit_relational_expr_ne: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr ">" any_expr + { + REDUCE_EXPR($1, $$, relational_expr_gt); + REDUCE_EXPR($3, $$, relational_expr_gt); + RELATIONAL_CODE($1, $3, >, $$, relational_expr_gt); + exit_relational_expr_gt: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr ">=" any_expr + { + REDUCE_EXPR($1, $$, relational_expr_ge); + REDUCE_EXPR($3, $$, relational_expr_ge); + RELATIONAL_CODE($1, $3, >=, $$, relational_expr_ge); + exit_relational_expr_ge: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + ; + + + bitwise_expr : any_expr "<<" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_shift_left); + REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_shift_left); + BITWISE_CODE($1, $3, <<, $$, bitwise_expr_shift_left); + exit_bitwise_expr_shift_left: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr ">>" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_shift_right); + REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_shift_right); + BITWISE_CODE($1, $3, >>, $$, bitwise_expr_shift_right); + exit_bitwise_expr_shift_right: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "&" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_and); + REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_and); + BITWISE_CODE($1, $3, &, $$, bitwise_expr_and); + exit_bitwise_expr_and: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "|" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_or); + REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_or); + BITWISE_CODE($1, $3, |, $$, bitwise_expr_or); + exit_bitwise_expr_or: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "^" any_expr + { + REDUCE_NUMERIC_EXPR($1, $$, bitwise_expr_xor); + REDUCE_NUMERIC_EXPR($3, $$, bitwise_expr_xor); + BITWISE_CODE($1, $3, ^, $$, bitwise_expr_xor); + exit_bitwise_expr_xor: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + ; + + + logical_expr : "not" any_expr + { + REDUCE_EXPR($2, $$, logical_expr_not); + CHECK_TYPE($2, GVT_BOOLEAN, $$, logical_expr_not); + $$.status = !$2.status; + $$.type = GVT_BOOLEAN; + exit_logical_expr_not: + EXIT_RESOLVED_VALUE($2); + } + | any_expr "and" any_expr + { + REDUCE_EXPR($1, $$, logical_expr_and); + CHECK_TYPE($1, GVT_BOOLEAN, $$, logical_expr_and); + REDUCE_EXPR($3, $$, logical_expr_and); + CHECK_TYPE($3, GVT_BOOLEAN, $$, logical_expr_and); + $$.status = $1.status && $3.status; + $$.type = GVT_BOOLEAN; + exit_logical_expr_and: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + | any_expr "or" any_expr + { + REDUCE_EXPR($1, $$, logical_expr_or); + CHECK_TYPE($1, GVT_BOOLEAN, $$, logical_expr_or); + REDUCE_EXPR($3, $$, logical_expr_or); + CHECK_TYPE($3, GVT_BOOLEAN, $$, logical_expr_or); + $$.status = $1.status || $3.status; + $$.type = GVT_BOOLEAN; + exit_logical_expr_or: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + ; + + + ternary_expr : any_expr "?" any_expr ":" any_expr + { + REDUCE_EXPR($1, $$, ternary_expr); + CHECK_TYPE($1, GVT_BOOLEAN, $$, ternary_expr); + if ($1.status) + COPY_RESOLVED_VALUE($$, $3); + else + COPY_RESOLVED_VALUE($$, $5); + exit_ternary_expr: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + EXIT_RESOLVED_VALUE($5); + } + ; + + +/* Conversions et méthodes particulières de types */ + + convert_2_bytes : any_expr ".to_s" + { + int __ret; + + if ($1.type == GVT_UNSIGNED_INTEGER) + { + __ret = asprintf(&$$.bytes.data, "%llu", $1.unsigned_integer); + if (__ret == -1) EXIT_WITH_ERR($$, convert_2_bytes_to_s); + + $$.bytes.len = __ret; + $$.type = GVT_BYTES; + + } + else if ($1.type == GVT_SIGNED_INTEGER) + { + __ret = asprintf(&$$.bytes.data, "%lld", $1.signed_integer); + if (__ret == -1) EXIT_WITH_ERR($$, convert_2_bytes_to_s); + + $$.bytes.len = __ret; + $$.type = GVT_BYTES; + + } + else + EXIT_WITH_ERR($$, convert_2_bytes_to_s); + + exit_convert_2_bytes_to_s: + EXIT_RESOLVED_VALUE($1); + } + | any_expr ".to_s(" ENCODING_NAME ")" + { + /** + * Cf. https://fossies.org/linux/libiconv/man/iconv_open.3.html + */ + + char *__fromcode; + gsize __bytes_read; + gsize __bytes_written; + + if ($1.type != GVT_BYTES) + EXIT_WITH_ERR($$, convert_2_bytes_to_s_encoding); + + __fromcode = strndup($3.data, $3.len); + + $$.bytes.data = g_convert($1.bytes.data, $1.bytes.len, + __fromcode, "", &__bytes_read, &__bytes_written, NULL); + + free(__fromcode); + + if (__bytes_read != $1.bytes.len) + EXIT_WITH_ERR($$, convert_2_bytes_to_s_encoding); + + $$.bytes.len = __bytes_written; + $$.type = GVT_BYTES; + + exit_convert_2_bytes_to_s_encoding: + EXIT_RESOLVED_VALUE($1); + } + ; + + + convert_2_integer : any_expr ".length" + { + if ($1.type != GVT_BYTES) + EXIT_WITH_ERR($$, convert_2_integer_to_s); + + $$.unsigned_integer = $1.bytes.len; + $$.type = GVT_UNSIGNED_INTEGER; + + exit_convert_2_integer_to_s: + EXIT_RESOLVED_VALUE($1); + } + | any_expr ".to_i" + { + char *__n; + char *__end; + + if ($1.type == GVT_FLOAT) + { + if ($1.floating_number < 0) + { + $$.signed_integer = $1.floating_number; + $$.type = GVT_SIGNED_INTEGER; + } + else + { + $$.unsigned_integer = $1.floating_number; + $$.type = GVT_UNSIGNED_INTEGER; + } + + } + + else if ($1.type == GVT_BOOLEAN) + { + $$.unsigned_integer = $1.status ? 1 : 0; + $$.type = GVT_UNSIGNED_INTEGER; + } + + else if ($1.type == GVT_BYTES) + { + if ($1.bytes.len == 0) + EXIT_WITH_ERR($$, convert_2_integer_to_i); + + __n = malloc($1.bytes.len + 1); + memcpy(__n, $1.bytes.data, $1.bytes.len); + __n[$1.bytes.len] = '\0'; + + if ($1.bytes.data[0] == '-') + { + if ($1.bytes.len == 1) + EXIT_WITH_ERR($$, convert_2_integer_to_i); + + $$.signed_integer = strtoll(__n, &__end, 10); + $$.type = GVT_SIGNED_INTEGER; + + if (errno == EINVAL || errno == ERANGE) + EXIT_WITH_ERR($$, convert_2_integer_to_i); + + if (__end != &__n[$1.bytes.len]) + EXIT_WITH_ERR($$, convert_2_integer_to_i); + + } + else + { + if ($1.bytes.len == 1) + EXIT_WITH_ERR($$, convert_2_integer_to_i); + + $$.unsigned_integer = strtoull(__n, &__end, 10); + $$.type = GVT_UNSIGNED_INTEGER; + + if (errno == EINVAL || errno == ERANGE) + EXIT_WITH_ERR($$, convert_2_integer_to_i); + + if (__end != &__n[$1.bytes.len]) + EXIT_WITH_ERR($$, convert_2_integer_to_i); + + } + + free(__n); + + } + + else EXIT_WITH_ERR($$, convert_2_integer_to_i); + + exit_convert_2_integer_to_i: + EXIT_RESOLVED_VALUE($1); + } + | any_expr ".to_i(" any_expr ")" + { + int __base; + char *__n; + char *__end; + + if ($1.type == GVT_BYTES) + { + if ($1.bytes.len == 0) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + if ($3.type == GVT_UNSIGNED_INTEGER) + { + __base = $3.unsigned_integer; + if (__base < 2) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + } + else if ($3.type == GVT_SIGNED_INTEGER) + { + __base = $3.signed_integer; + if (__base < 2) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + } + else EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + __n = malloc($1.bytes.len + 1); + memcpy(__n, $1.bytes.data, $1.bytes.len); + __n[$1.bytes.len] = '\0'; + + if ($1.bytes.data[0] == '-') + { + if ($1.bytes.len == 1) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + $$.signed_integer = strtoll(__n, &__end, __base); + $$.type = GVT_SIGNED_INTEGER; + + if (errno == EINVAL || errno == ERANGE) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + if (__end != &__n[$1.bytes.len]) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + } + else + { + if ($1.bytes.len == 1) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + $$.unsigned_integer = strtoull(__n, &__end, __base); + $$.type = GVT_UNSIGNED_INTEGER; + + if (errno == EINVAL || errno == ERANGE) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + if (__end != &__n[$1.bytes.len]) + EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + } + + free(__n); + + } + + else EXIT_WITH_ERR($$, convert_2_integer_to_i_base); + + exit_convert_2_integer_to_i_base: + EXIT_RESOLVED_VALUE($1); + } + | any_expr ".size" + { + GRecordList *__list; + + if ($1.type != GVT_RECORD) EXIT_WITH_ERR($$, convert_2_integer_size); + if (!G_IS_RECORD_LIST($1.record)) EXIT_WITH_ERR($$, convert_2_integer_size); + + __list = G_RECORD_LIST($1.record); + + $$.unsigned_integer = g_record_list_count_records(__list); + $$.type = GVT_UNSIGNED_INTEGER; + + exit_convert_2_integer_size: + EXIT_RESOLVED_VALUE($1); + } + ; + + +/* Types de base */ + + boolean : "true" + { + $$.status = true; + $$.type = GVT_BOOLEAN; + } + | "false" + { + $$.status = false; + $$.type = GVT_BOOLEAN; + } + ; + + + integer : UNSIGNED_INTEGER + { + $$.unsigned_integer = $1; + $$.type = GVT_UNSIGNED_INTEGER; + } + | SIGNED_INTEGER + { + $$.signed_integer = $1; + $$.type = GVT_SIGNED_INTEGER; + } + ; + + + float : FLOAT + { + $$.floating_number = $1; + $$.type = GVT_FLOAT; + } + ; + + + bytes : bytes_concat { $$ = $1; } + | PLAIN_BYTES + { + $$.bytes.len = $1.len; + $$.bytes.data = malloc($1.len); + memcpy($$.bytes.data, $1.data, $1.len); + $$.type = GVT_BYTES; + } + | any_expr ".reverse" + { + size_t __i; + + CHECK_TYPE($1, GVT_BYTES, $$, bytes_reverse); + + $$.bytes.data = malloc($1.bytes.len); + $$.bytes.len = $1.bytes.len; + + for (__i = 0; __i < $1.bytes.len; __i++) + $$.bytes.data[__i] = $1.bytes.data[$1.bytes.len - __i - 1]; + + $$.type = GVT_BYTES; + + exit_bytes_reverse: + EXIT_RESOLVED_VALUE($1); + } + | any_expr ".substring" "(" any_expr "," any_expr ")" + { + unsigned long long __from; + unsigned long long __to; + + REDUCE_NUMERIC_EXPR($4, $$, bytes_reverse); + CHECK_TYPES($4, GVT_UNSIGNED_INTEGER, GVT_SIGNED_INTEGER, $$, bytes_substring); + REDUCE_NUMERIC_EXPR($6, $$, bytes_reverse); + CHECK_TYPES($6, GVT_UNSIGNED_INTEGER, GVT_SIGNED_INTEGER, $$, bytes_substring); + + __from = ($4.type == GVT_UNSIGNED_INTEGER ? $4.unsigned_integer : $4.signed_integer); + __to = ($6.type == GVT_UNSIGNED_INTEGER ? $6.unsigned_integer : $6.signed_integer); + + if (__from > __to) EXIT_WITH_ERR($$, bytes_substring); + if (__to >= $1.bytes.len) EXIT_WITH_ERR($$, bytes_substring); + + $$.bytes.len = __to - __from + 1; + $$.bytes.data = malloc($$.bytes.len); + + memcpy($$.bytes.data, &$1.bytes.data[__from], $$.bytes.len); + + $$.type = GVT_BYTES; + + exit_bytes_substring: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($4); + EXIT_RESOLVED_VALUE($6); + } + ; + + bytes_concat : raw_bytes { $$ = $1; }; + | bytes_concat raw_bytes + { + $$.bytes.len = $1.bytes.len + $2.bytes.len; + $$.bytes.data = malloc($$.bytes.len); + memcpy($$.bytes.data, $1.bytes.data, $1.bytes.len); + memcpy($$.bytes.data + $1.bytes.len, $2.bytes.data, $2.bytes.len); + $$.type = GVT_BYTES; + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($2); + } + ; + + raw_bytes : RAW_BYTES + { + $$.bytes.len = $1.len; + $$.bytes.data = malloc($1.len); + memcpy($$.bytes.data, $1.data, $1.len); + $$.type = GVT_BYTES; + } + | RAW_BYTE + { + $$.bytes.len = 1; + $$.bytes.data = malloc(1); + $$.bytes.data[0] = $1; + $$.type = GVT_BYTES; + } + | RAW_BYTES_WITH_ENDING_DOT + { + $$.bytes.len = $1.len; + $$.bytes.data = malloc($1.len); + memcpy($$.bytes.data, $1.data, $1.len); + $$.type = GVT_BYTES; + } + ; + + +/* Tableau d'éléments variés */ + + array : "[" "]" + { + $$.array = g_kaitai_array_new(); + $$.type = GVT_ARRAY; + } + | "[" array_items "]" + { + $$ = $2; + } + ; + + + array_items : any_expr + { + $$.array = g_kaitai_array_new(); + $$.type = GVT_ARRAY; + + g_kaitai_array_append_item($$.array, &$1); + + EXIT_RESOLVED_VALUE($1); + + } + | array_items "," any_expr + { + $$ = $1; + g_kaitai_array_append_item($$.array, &$3); + EXIT_RESOLVED_VALUE($3); + } + ; + + +/* Accès aux objets Kaitai manipulés */ + + field : IDENTIFIER + { + $$.record = g_match_record_find_by_name(locals->parent, + $1.data, $1.len, + DIRECT_SEARCH_DEEP_LEVEL); + + if ($$.record != NULL) + $$.type = GVT_RECORD; + + /* Si aucune correspondance, le contenu brut est utilisé */ + else + { + $$.bytes.len = $1.len; + $$.bytes.data = malloc($1.len); + memcpy($$.bytes.data, $1.data, $1.len); + $$.type = GVT_BYTES; + } + + } + | "_root" + { + $$.record = get_root_record(locals); + if ($$.record == NULL) SET_ERR($$); + else $$.type = GVT_RECORD; + } + | "_parent" + { + $$.record = get_parent_record(locals); + if ($$.record == NULL) SET_ERR($$); + else $$.type = GVT_RECORD; + } + | "_" + { + $$.record = get_last_record(locals); + if ($$.record == NULL) SET_ERR($$); + else $$.type = GVT_RECORD; + } + | any_expr "." IDENTIFIER + { + if ($1.type != GVT_RECORD) + EXIT_WITH_ERR($$, field_dot); + + $$.record = g_match_record_find_by_name($1.record, + $3.data, $3.len, + DIRECT_SEARCH_DEEP_LEVEL); + + if ($$.record == NULL) + EXIT_WITH_ERR($$, field_dot); + + $$.type = GVT_RECORD; + + exit_field_dot: + EXIT_RESOLVED_VALUE($1); + } + | any_expr "[" any_expr "]" + { + size_t __index; + GRecordList *__list; + size_t __count; + GKaitaiArray *__array; + + /* Indice de l'élément auquel accéder */ + + REDUCE_NUMERIC_EXPR($3, $$, field_indexed); + + if ($3.type == GVT_UNSIGNED_INTEGER) + __index = $3.unsigned_integer; + else + EXIT_WITH_ERR($$, field_indexed); + + /* Série à consulter */ + + REDUCE_EXPR($1, $$, field_indexed); + + if ($1.type == GVT_RECORD && G_IS_RECORD_LIST($1.record)) + { + __list = G_RECORD_LIST($1.record); + __count = g_record_list_count_records(__list); + + if (__index >= __count) + EXIT_WITH_ERR($$, field_indexed); + + $$.record = g_record_list_get_record(__list, __index); + + if ($$.record == NULL) + EXIT_WITH_ERR($$, field_indexed); + + $$.type = GVT_RECORD; + + } + + else if ($1.type == GVT_ARRAY) + { + __array = G_KAITAI_ARRAY($1.array); + __count = g_kaitai_array_count_items(__array); + + if (__index >= __count) + EXIT_WITH_ERR($$, field_indexed); + + if (!g_kaitai_array_get_item(__array, __index, &$$)) + EXIT_WITH_ERR($$, field_indexed); + + } + + else + EXIT_WITH_ERR($$, field_indexed); + + exit_field_indexed: + EXIT_RESOLVED_VALUE($1); + EXIT_RESOLVED_VALUE($3); + } + ; + + + enumeration : IDENTIFIER "::" IDENTIFIER + { + if (!g_match_record_resolve_enum(locals->parent, &$1, &$3, &$$)) + SET_ERR($$); + } + + + stream : "_io" + { + GBinContent *__content; + mrange_t __range; + vmpa2t __next; + + if (locals->last == NULL) + { + __content = g_match_record_get_content(locals->root); + + g_binary_content_compute_start_pos(__content, &__next); + + } + else + { + __content = g_match_record_get_content(locals->last); + + g_match_record_get_range(locals->last, &__range); + compute_mrange_end_addr(&__range, &__next); + + } + + $$.stream = g_kaitai_stream_new(__content, &__next); + $$.type = GVT_STREAM; + + g_object_unref(G_OBJECT(__content)); + + } + | any_expr "._io" + { + GBinContent *__content; + mrange_t __range; + + if ($1.type != GVT_RECORD) + EXIT_WITH_ERR($$, stream_io); + + __content = g_match_record_get_content($1.record); + g_match_record_get_range($1.record, &__range); + + $$.stream = g_kaitai_stream_new(__content, get_mrange_addr(&__range)); + $$.type = GVT_STREAM; + + g_object_unref(G_OBJECT(__content)); + + exit_stream_io: + EXIT_RESOLVED_VALUE($1); + } + ; + + stream_meths : stream ".eof" + { + $$.status = g_kaitai_stream_has_reached_eof($1.stream);; + $$.type = GVT_BOOLEAN; + + EXIT_RESOLVED_VALUE($1); + + } + ; + +%% + + +/****************************************************************************** +* * +* Paramètres : yyscanner = décodeur impliqué dans le processus. * +* locals = variables locales pour les résolutions de types. * +* out = valeur entière résultante. [OUT] * +* msg = message d'erreur. * +* * +* Description : Affiche un message d'erreur suite à l'analyse en échec. * +* * +* Retour : 0 * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int yyerror(yyscan_t yyscanner, const kaitai_scope_t *locals, resolved_value_t *resolved, const char *msg) +{ + printf("YYERROR line %d: %s\n", yyget_lineno(yyscanner), msg); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* text = définitions des règles à charger. * +* length = longueur de ces définitions. * +* out = valeur générique résultante. [OUT] * +* * +* Description : Interprète une expression en une valeur quelconque. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _resolve_kaitai_expression_as_any(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out) +{ + bool result; /* Bilan à renvoyer */ + yyscan_t lexstate; /* Gestion d'analyse lexicale */ + char *real_text; /* Zone de travail effective */ + size_t real_length; /* Taille associée */ + YY_BUFFER_STATE state; /* Contexte d'analyse */ + int status; /* Bilan d'une analyse */ + + result = false; + + kaitai_lex_init(&lexstate); + + assert(length > 0); + + if (text[length - 1] == '.') + { + /** + * Si le contenu à analyser se termine par un point, la position finale + * de ce point est prise en compte. Pour ce faire, le marqueur "$" des + * expressions régulières est sollicité. Hors, ce dernier n'est reconnu + * que pour le caractère "\n" terminant une ligne. + * + * On l'ajoute donc artificiellement. + */ + + real_length = length + 1; + + real_text = malloc(real_length); + memcpy(real_text, text, length); + real_text[length] = '\n'; + + } + else + { + real_text = (char *)text; + real_length = length; + } + + state = kaitai__scan_bytes(real_text, real_length, lexstate); + + if (text[length - 1] == '.') + free(real_text); + + status = yyparse(lexstate, locals, out); + + result = (status == EXIT_SUCCESS); + + yy_delete_buffer(state, lexstate); + + kaitai_lex_destroy(lexstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* text = définitions des règles à charger. * +* length = longueur de ces définitions. * +* out = valeur générique résultante. [OUT] * +* * +* Description : Interprète une expression en une valeur quelconque. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool resolve_kaitai_expression_as_any(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out) +{ + bool result; /* Bilan à renvoyer */ + + result = _resolve_kaitai_expression_as_any(locals, text, length, out); + + return result; + +} + + + +/****************************************************************************** +* * +* Paramètres : in_out = expression résolue traitée. [OUT] * +* * +* Description : Traduit les éventuels champs impliqués dans une expression. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool reduce_resolved_kaitai_expression(resolved_value_t *in_out) +{ + bool result; /* Bilan à renvoyer */ + resolved_value_t deeper; /* Précision supplémentaire */ + + result = true; + + while (result && in_out->type == GVT_RECORD) + { + if (G_IS_RECORD_BIT_FIELD(in_out->record)) + result = g_record_bit_field_get_value(G_RECORD_BIT_FIELD(in_out->record), &deeper); + + else if (G_IS_RECORD_DELAYED(in_out->record)) + result = g_record_delayed_compute_value(G_RECORD_DELAYED(in_out->record), &deeper); + + else if (G_IS_RECORD_ITEM(in_out->record)) + result = g_record_item_get_value(G_RECORD_ITEM(in_out->record), &deeper); + + else + break; + + if (result) + { + EXIT_RESOLVED_VALUE(*in_out); + *in_out = deeper; + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* text = définitions des règles à charger. * +* length = longueur de ces définitions. * +* out = valeur entière résultante. [OUT] * +* * +* Description : Interprète une expression en valeur ciblée entière. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool resolve_kaitai_expression_as_integer(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out) +{ + bool result; /* Bilan à renvoyer */ + + result = _resolve_kaitai_expression_as_any(locals, text, length, out); + + if (result) + result = reduce_resolved_kaitai_expression(out); + + if (result) + result = (out->type == GVT_UNSIGNED_INTEGER || out->type == GVT_SIGNED_INTEGER); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* text = définitions des règles à charger. * +* length = longueur de ces définitions. * +* out = valeur booléenne résultante. [OUT] * +* * +* Description : Interprète une expression en valeur ciblée booléenne. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool resolve_kaitai_expression_as_boolean(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out) +{ + bool result; /* Bilan à renvoyer */ + + result = _resolve_kaitai_expression_as_any(locals, text, length, out); + + if (result) + result = reduce_resolved_kaitai_expression(out); + + if (result) + { + if (out->type == GVT_UNSIGNED_INTEGER) + { + out->status = (out->unsigned_integer != 0); + out->type = GVT_BOOLEAN; + } + else if (out->type == GVT_SIGNED_INTEGER) + { + out->status = (out->signed_integer != 0); + out->type = GVT_BOOLEAN; + } + else if (out->type == GVT_FLOAT) + { + out->status = (out->floating_number != 0); + out->type = GVT_BOOLEAN; + } + + } + + if (result && out->type != GVT_BOOLEAN) + { + EXIT_RESOLVED_VALUE(*out); + result = false; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* text = définitions des règles à charger. * +* length = longueur de ces définitions. * +* out = valeur booléenne résultante. [OUT] * +* * +* Description : Interprète une expression en série d'octets. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool resolve_kaitai_expression_as_bytes(const kaitai_scope_t *locals, const char *text, size_t length, resolved_value_t *out) +{ + bool result; /* Bilan à renvoyer */ + char ch; /* Caractère unique spécifié */ + sized_string_t converted; /* Conversion finale ? */ + + result = _resolve_kaitai_expression_as_any(locals, text, length, out); + + if (result) + result = reduce_resolved_kaitai_expression(out); + + if (result) + { + if (out->type == GVT_UNSIGNED_INTEGER) + { + ch = out->unsigned_integer; + result = (ch <= 0xff); + + if (result) + { + EXIT_RESOLVED_VALUE(*out); + + out->bytes.data = malloc(sizeof(char)); + out->bytes.data[0] = ch; + out->bytes.len = 1; + out->type = GVT_BYTES; + + } + + } + + else if (out->type == GVT_ARRAY) + { + result = g_kaitai_array_convert_to_bytes(out->array, &converted); + + if (result) + { + EXIT_RESOLVED_VALUE(*out); + + out->bytes = converted; + out->type = GVT_BYTES; + + } + + } + + } + + if (result && out->type != GVT_BYTES) + { + EXIT_RESOLVED_VALUE(*out); + result = false; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* text = définitions des règles à charger. * +* length = longueur de ces définitions. * +* stream = flux de données pour Kaitai résultant. [OUT] * +* * +* Description : Interprète une expression en flux de données pour Kaitai. * +* * +* Retour : Bilan à retourner. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool resolve_kaitai_expression_as_stream(const kaitai_scope_t *locals, const char *text, size_t length, GKaitaiStream **stream) +{ + bool result; /* Bilan à renvoyer */ + resolved_value_t out; /* Elément générique obtenu */ + + result = _resolve_kaitai_expression_as_any(locals, text, length, &out); + + if (result) + { + assert(out.type == GVT_STREAM); + *stream = out.stream; + } + else + *stream = NULL; + + return result; + +} diff --git a/plugins/kaitai/import.c b/plugins/kaitai/import.c new file mode 100644 index 0000000..0412ff7 --- /dev/null +++ b/plugins/kaitai/import.c @@ -0,0 +1,300 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * import.c - localisation de fichiers de définitions externes + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "import.h" + + +#include <libgen.h> +#include <malloc.h> +#include <string.h> + + +#include <common/environment.h> +#include <core/logs.h> + + + +/* Charge un type Kaitai à partir d'une définition voisine. */ +static GKaitaiType *import_relative_kaitai_definition(const char *, const char *); + +/* Charge un type Kaitai depuis un emplacement de $KSPATH. */ +static GKaitaiType *import_kaitai_definition_from_env(const char *); + +/* Charge un interpréteur pour une définition voisine. */ +static GKaitaiStruct *load_relative_kaitai_definition(const char *, const char *); + +/* Charge un interpréteur depuis un emplacement de $KSPATH. */ +static GKaitaiStruct *load_kaitai_definition_from_env(const char *); + + + +/****************************************************************************** +* * +* Paramètres : target = désignation de la définition à retrouver. * +* reference = éventuel fichier pour les positions relatives. * +* * +* Description : Charge un type Kaitai à partir d'une définition voisine. * +* * +* Retour : Type valide en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GKaitaiType *import_relative_kaitai_definition(const char *target, const char *reference) +{ + GKaitaiType *result; /* Structure chargée à renvoyer*/ + char *tmp; /* Zone de travail temporaire */ + char *base; /* Base de recherche */ + char *filename; /* Nom de fichier à tester */ + int ret; /* Bilan d'une construction */ + + result = NULL; + + tmp = strdup(reference); + base = dirname(tmp); + + ret = asprintf(&filename, "%s%c%s.ksy", base, G_DIR_SEPARATOR, target); + if (ret == -1) goto build_error; + + result = g_kaitai_type_new_as_import(target, filename); + + free(filename); + + build_error: + + free(tmp); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de la définition à retrouver. * +* * +* Description : Charge un type Kaitai depuis un emplacement de $KSPATH. * +* * +* Retour : Type valide en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GKaitaiType *import_kaitai_definition_from_env(const char *target) +{ + GKaitaiType *result; /* Structure chargée à renvoyer*/ + char *paths; /* Emplacements de greffons */ + char *save; /* Sauvegarde pour ré-entrance */ + char *path; /* Chemin à fouiller */ + char *filename; /* Nom de fichier à tester */ + int ret; /* Bilan d'une construction */ + + result = NULL; + + paths = get_env_var("KSPATH"); + + save = NULL; /* gcc... */ + + for (path = strtok_r(paths, ":", &save); + path != NULL; + path = strtok_r(NULL, ":", &save)) + { + ret = asprintf(&filename, "%s%c%s.ksy", path, G_DIR_SEPARATOR, target); + if (ret == -1) + { + LOG_ERROR_N("asprintf"); + continue; + } + + result = g_kaitai_type_new_as_import(target, filename); + + if (result != NULL) + log_variadic_message(LMT_PROCESS, _("Found a required Kaitai definition to import: %s"), filename); + + free(filename); + + } + + free(paths); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de la définition à retrouver. * +* reference = éventuel fichier pour les positions relatives. * +* * +* Description : Met en place un type Kaitai pour une définition désignée. * +* * +* Retour : Type valide en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiType *import_kaitai_definition(const char *target, const char *reference) +{ + GKaitaiType *result; /* Structure chargée à renvoyer*/ + + result = NULL; + + if (reference != NULL) + result = import_relative_kaitai_definition(target, reference); + + if (result == NULL) + result = import_kaitai_definition_from_env(target); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de la définition à retrouver. * +* reference = éventuel fichier pour les positions relatives. * +* * +* Description : Charge un interpréteur pour une définition voisine. * +* * +* Retour : Interprétateur valide en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GKaitaiStruct *load_relative_kaitai_definition(const char *target, const char *reference) +{ + GKaitaiStruct *result; /* Structure chargée à renvoyer*/ + char *tmp; /* Zone de travail temporaire */ + char *base; /* Base de recherche */ + char *filename; /* Nom de fichier à tester */ + int ret; /* Bilan d'une construction */ + + result = NULL; + + tmp = strdup(reference); + base = dirname(tmp); + + ret = asprintf(&filename, "%s%c%s.ksy", base, G_DIR_SEPARATOR, target); + if (ret == -1) goto build_error; + + result = g_kaitai_structure_new_from_file(filename); + + free(filename); + + build_error: + + free(tmp); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de la définition à retrouver. * +* * +* Description : Charge un interpréteur depuis un emplacement de $KSPATH. * +* * +* Retour : Interprétateur valide en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GKaitaiStruct *load_kaitai_definition_from_env(const char *target) +{ + GKaitaiStruct *result; /* Structure chargée à renvoyer*/ + char *paths; /* Emplacements de greffons */ + char *save; /* Sauvegarde pour ré-entrance */ + char *path; /* Chemin à fouiller */ + char *filename; /* Nom de fichier à tester */ + int ret; /* Bilan d'une construction */ + + result = NULL; + + paths = get_env_var("KSPATH"); + + save = NULL; /* gcc... */ + + for (path = strtok_r(paths, ":", &save); + path != NULL; + path = strtok_r(NULL, ":", &save)) + { + ret = asprintf(&filename, "%s%c%s.ksy", path, G_DIR_SEPARATOR, target); + if (ret == -1) + { + LOG_ERROR_N("asprintf"); + continue; + } + + result = g_kaitai_structure_new_from_file(filename); + + if (result != NULL) + log_variadic_message(LMT_PROCESS, _("Found a required Kaitai definition: %s"), filename); + + free(filename); + + } + + free(paths); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : target = désignation de la définition à retrouver. * +* reference = éventuel fichier pour les positions relatives. * +* * +* Description : Met en place un interpréteur pour une définition désignée. * +* * +* Retour : Interprétateur valide en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiStruct *load_kaitai_definition(const char *target, const char *reference) +{ + GKaitaiStruct *result; /* Structure chargée à renvoyer*/ + + result = NULL; + + if (reference != NULL) + result = load_relative_kaitai_definition(target, reference); + + if (result == NULL) + result = load_kaitai_definition_from_env(target); + + return result; + +} diff --git a/plugins/kaitai/import.h b/plugins/kaitai/import.h new file mode 100644 index 0000000..66a0f5a --- /dev/null +++ b/plugins/kaitai/import.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * import.h - prototypes pour la localisation de fichiers de définitions externes + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_IMPORT_H +#define _PLUGINS_KAITAI_IMPORT_H + + +#include "parsers/struct.h" +#include "parsers/type.h" + + + +/* Met en place un type Kaitai pour une définition désignée. */ +GKaitaiType *import_kaitai_definition(const char *, const char *); + +/* Met en place un interpréteur pour une définition désignée. */ +GKaitaiStruct *load_kaitai_definition(const char *, const char *); + + + +#endif /* _PLUGINS_KAITAI_IMPORT_H */ diff --git a/plugins/kaitai/parser-int.h b/plugins/kaitai/parser-int.h new file mode 100644 index 0000000..8bac523 --- /dev/null +++ b/plugins/kaitai/parser-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser-int.h - prototypes pour les spécifications internes d'un lecteur Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_PARSER_INT_H +#define PLUGINS_KAITAI_PARSER_INT_H + + +#include "parser.h" + + + +/* Parcourt un contenu binaire selon des spécifications Kaitai. */ +typedef bool (* parse_kaitai_fc) (GKaitaiParser *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **); + + + +/* Spécification d'un lecteur Kaitai (instance) */ +struct _GKaitaiParser +{ + GObject parent; /* A laisser en premier */ + +}; + +/* Spécification d'un lecteur Kaitai (classe) */ +struct _GKaitaiParserClass +{ + GObjectClass parent; /* A laisser en premier */ + + parse_kaitai_fc parse; /* Phase d'analyse de contenu */ + +}; + + + +#endif /* PLUGINS_KAITAI_PARSER_INT_H */ diff --git a/plugins/kaitai/parser.c b/plugins/kaitai/parser.c new file mode 100644 index 0000000..cfe1aa1 --- /dev/null +++ b/plugins/kaitai/parser.c @@ -0,0 +1,166 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.c - spécification d'un lecteur Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "parser.h" + + +#include <assert.h> + + +#include "parser-int.h" + + + +/* Initialise la classe des lecteurs de spécification Kaitai. */ +static void g_kaitai_parser_class_init(GKaitaiParserClass *); + +/* Initialise un lecteur de spécification Kaitai. */ +static void g_kaitai_parser_init(GKaitaiParser *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_parser_dispose(GKaitaiParser *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_parser_finalize(GKaitaiParser *); + + + +/* Indique le type défini pour un lecteur de spécification Kaitai. */ +G_DEFINE_TYPE(GKaitaiParser, g_kaitai_parser, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des lecteurs de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_parser_class_init(GKaitaiParserClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_parser_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_parser_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : parser = instance à initialiser. * +* * +* Description : Initialise un lecteur de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_parser_init(GKaitaiParser *parser) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : parser = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_parser_dispose(GKaitaiParser *parser) +{ + G_OBJECT_CLASS(g_kaitai_parser_parent_class)->dispose(G_OBJECT(parser)); + +} + + +/****************************************************************************** +* * +* Paramètres : parser = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_parser_finalize(GKaitaiParser *parser) +{ + G_OBJECT_CLASS(g_kaitai_parser_parent_class)->finalize(G_OBJECT(parser)); + +} + + +/****************************************************************************** +* * +* Paramètres : parser = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* epos = tête de lecture courante. [OUT] * +* record = noeud d'arborescence d'éléments rencontrés. [OUT] * +* * +* Description : Parcourt un contenu binaire selon des spécifications Kaitai. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_parser_parse_content(GKaitaiParser *parser, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record) +{ + bool result; /* Bilan à retourner */ + GKaitaiParserClass *class; /* Classe de l'instance */ + + *record = NULL; + + class = G_KAITAI_PARSER_GET_CLASS(parser); + + result = class->parse(parser, locals, content, epos, record); + + if (result && *record != NULL) + remember_last_record(locals, *record); + + assert((!result && *record == NULL) || result); + + return result; + +} diff --git a/plugins/kaitai/parser.h b/plugins/kaitai/parser.h new file mode 100644 index 0000000..64d759d --- /dev/null +++ b/plugins/kaitai/parser.h @@ -0,0 +1,63 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.h - prototypes pour la spécification d'un lecteur Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_PARSER_H +#define PLUGINS_KAITAI_PARSER_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include <analysis/content.h> + + +#include "record.h" +#include "scope.h" + + + +#define G_TYPE_KAITAI_PARSER g_kaitai_parser_get_type() +#define G_KAITAI_PARSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_PARSER, GKaitaiParser)) +#define G_IS_KAITAI_PARSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_PARSER)) +#define G_KAITAI_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_PARSER, GKaitaiParserClass)) +#define G_IS_KAITAI_PARSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_PARSER)) +#define G_KAITAI_PARSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_PARSER, GKaitaiParserClass)) + + +/* Spécification d'un lecteur Kaitai (instance) */ +typedef struct _GKaitaiParser GKaitaiParser; + +/* Spécification d'un lecteur Kaitai (classe) */ +typedef struct _GKaitaiParserClass GKaitaiParserClass; + + +/* Indique le type défini pour un lecteur de spécification Kaitai. */ +GType g_kaitai_parser_get_type(void); + +/* Parcourt un contenu binaire selon des spécifications Kaitai. */ +bool g_kaitai_parser_parse_content(GKaitaiParser *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **); + + + +#endif /* PLUGINS_KAITAI_PARSER_H */ diff --git a/plugins/kaitai/parsers/Makefile.am b/plugins/kaitai/parsers/Makefile.am new file mode 100644 index 0000000..c7e313b --- /dev/null +++ b/plugins/kaitai/parsers/Makefile.am @@ -0,0 +1,25 @@ + +noinst_LTLIBRARIES = libkaitaiparsers.la + +libkaitaiparsers_la_SOURCES = \ + attribute-int.h \ + attribute.h attribute.c \ + enum-int.h \ + enum.h enum.c \ + instance-int.h \ + instance.h instance.c \ + meta-int.h \ + meta.h meta.c \ + struct-int.h \ + struct.h struct.c \ + switch-int.h \ + switch.h switch.c \ + type-int.h \ + type.h type.c + +libkaitaiparsers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaiparsers_la_SOURCES:%c=) diff --git a/plugins/kaitai/parsers/attribute-int.h b/plugins/kaitai/parsers/attribute-int.h new file mode 100644 index 0000000..7d37af3 --- /dev/null +++ b/plugins/kaitai/parsers/attribute-int.h @@ -0,0 +1,107 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * attribute-int.h - prototypes pour les spécifications internes d'un attribut Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H +#define _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H + + +#include "attribute.h" +#include "switch.h" +#include "../parser-int.h" + + + +/* Indique l'étiquette à utiliser pour identifier un attribut. */ +typedef const char * (* get_attribute_label_fc) (const GKaitaiAttribute *); + +/* Spécification d'un attribut Kaitai (instance) */ +struct _GKaitaiAttribute +{ + GKaitaiParser parent; /* A laisser en premier */ + + char *raw_id; /* Identifiant Kaitai */ + char *orig_id; /* Identifiant humain */ + + char *doc; /* Eventuelle documentation */ + + KaitaiAttributePayload payload; /* Forme de la spécialisation */ + + struct + { + /* KAP_FIXED_CONTENT */ + sized_string_t fixed_content; /* Données brutes attendues */ + + /* KAP_BIT_FIELD_TYPE */ + uint8_t bf_size; /* Nombre de bits visés */ + + /* KAP_BASIC_TYPE */ + struct + { + BaseType basic; /* Type de base */ + + bool is_string; /* Renvoi vers une chaîne */ + + SourceEndian endian; /* Boutisme forcé ? */ + bool has_endian; /* Présence de cette force */ + + }; + + /* KAP_USER_TYPE */ + char *named_type; /* Type particulier */ + + /* KAP_DYNAMIC_TYPE */ + GKaitaiSwitch *switchon; /* Détermination dynamique */ + + }; + + /* KAP_SIZED */ + char *fixed_size; /* Taille déterminée */ + + KaitaiAttributeRepetition repetition; /* Forme de répétition */ + char *repeat_controller; /* Indication sur la répétition*/ + + char *condition; /* Condition de chargement */ + + sized_string_t terminator; /* Marqueur de fin éventuel */ + bool consume; /* Consommation dans le flux */ + bool include; /* Intégration de ce marqueur */ + bool eos_error; /* Gestion des erreurs en bout */ + +}; + +/* Spécification d'un attribut Kaitai (classe) */ +struct _GKaitaiAttributeClass +{ + GKaitaiParserClass parent; /* A laisser en premier */ + + get_attribute_label_fc get_label; /* Désignation d'une étiquette */ + +}; + + +/* Met en place un lecteur d'attribut Kaitai. */ +bool g_kaitai_attribute_create(GKaitaiAttribute *, GYamlNode *, bool); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H */ diff --git a/plugins/kaitai/parsers/attribute.c b/plugins/kaitai/parsers/attribute.c new file mode 100644 index 0000000..6050bb1 --- /dev/null +++ b/plugins/kaitai/parsers/attribute.c @@ -0,0 +1,2213 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * attribute.c - spécification d'un attribut Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "attribute.h" + + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + + +#include <analysis/contents/restricted.h> +#include <plugins/yaml/pair.h> + + +#include "attribute-int.h" +#include "../expression.h" +#include "../scope.h" +#include "../records/bits.h" +#include "../records/empty.h" +#include "../records/item.h" +#include "../records/list.h" + + + +/* -------------------- CORRESPONDANCE ENTRE ATTRIBUT ET BINAIRE -------------------- */ + + +/* Initialise la classe des attributs de spécification Kaitai. */ +static void g_kaitai_attribute_class_init(GKaitaiAttributeClass *); + +/* Initialise un attribut de spécification Kaitai. */ +static void g_kaitai_attribute_init(GKaitaiAttribute *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_attribute_dispose(GKaitaiAttribute *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_attribute_finalize(GKaitaiAttribute *); + +/* Traduit en champ de bits une chaîne de caractères. */ +static bool g_kaitai_attribute_resolve_bit_field(GKaitaiAttribute *, const char *); + +/* Traduit en type concret une chaîne de caractères. */ +static bool g_kaitai_attribute_resolve_type(GKaitaiAttribute *, const char *); + +/* Valide la cohérence des informations portées par l'attribut. */ +static bool g_kaitai_attribute_check(const GKaitaiAttribute *); + +/* Copie le coeur de la définition d'un lecteur d'attribut. */ +static GKaitaiAttribute *g_kaitai_attribute_dup_for(const GKaitaiAttribute *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Parcourt un contenu binaire selon des spécifications Kaitai. */ +static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **); + +/* Extrait d'un contenu une série d'octets avec terminaison. */ +static bool g_kaitai_attribute_parse_terminated_bytes(GKaitaiAttribute *, const kaitai_scope_t *, GBinContent *, vmpa2t *, GMatchRecord **); + +/* Détermine la zone de couverture finale d'une correspondance. */ +static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttribute *, const kaitai_scope_t *, const GBinContent *, const vmpa2t *, phys_t *, mrange_t *); + +/* Parcourt un contenu binaire selon des spécifications Kaitai. */ +static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **); + + + +/* ---------------------------------------------------------------------------------- */ +/* CORRESPONDANCE ENTRE ATTRIBUT ET BINAIRE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un attribut de la spécification Kaitai. */ +G_DEFINE_TYPE(GKaitaiAttribute, g_kaitai_attribute, G_TYPE_KAITAI_PARSER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des attributs de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_attribute_class_init(GKaitaiAttributeClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GKaitaiParserClass *parser; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_attribute_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_attribute_finalize; + + parser = G_KAITAI_PARSER_CLASS(klass); + + parser->parse = (parse_kaitai_fc)g_kaitai_attribute_parse_content; + + klass->get_label = g_kaitai_attribute_get_raw_id; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = instance à initialiser. * +* * +* Description : Initialise un attribut de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_attribute_init(GKaitaiAttribute *attrib) +{ + attrib->raw_id = NULL; + attrib->orig_id = NULL; + + attrib->doc = NULL; + + attrib->payload = KAP_UNINITIALIZED; + + attrib->repetition = KAR_NO_REPETITION; + attrib->repeat_controller = NULL; + + attrib->condition = NULL; + + init_szstr(&attrib->terminator); + attrib->consume = true; + attrib->include = false; + attrib->eos_error = true; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_attribute_dispose(GKaitaiAttribute *attrib) +{ + if (attrib->payload & KAP_DYNAMIC_TYPE) + g_clear_object(&attrib->switchon); + + G_OBJECT_CLASS(g_kaitai_attribute_parent_class)->dispose(G_OBJECT(attrib)); + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_attribute_finalize(GKaitaiAttribute *attrib) +{ + if (attrib->raw_id != NULL) + free(attrib->raw_id); + + if (attrib->orig_id != NULL) + free(attrib->orig_id); + + if (attrib->doc != NULL) + free(attrib->doc); + + if (attrib->payload & KAP_FIXED_CONTENT) + exit_szstr(&attrib->fixed_content); + + else if (attrib->payload & KAP_USER_TYPE) + free(attrib->named_type); + + if (attrib->fixed_size != NULL) + free(attrib->fixed_size); + + if (attrib->repeat_controller != NULL) + free(attrib->repeat_controller); + + if (attrib->condition != NULL) + free(attrib->condition); + + exit_szstr(&attrib->terminator); + + G_OBJECT_CLASS(g_kaitai_attribute_parent_class)->finalize(G_OBJECT(attrib)); + +} + + +/****************************************************************************** +* * +* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. * +* * +* Description : Construit un lecteur d'attribut Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiAttribute *g_kaitai_attribute_new(GYamlNode *parent) +{ + GKaitaiAttribute *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_ATTRIBUTE, NULL); + + if (!g_kaitai_attribute_create(result, parent, false /* TODO : REMME ? */)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à initialiser pleinement.* +* parent = noeud Yaml contenant l'attribut à constituer. * +* need_id = encadre la présence d'un champ "id". * +* * +* Description : Met en place un lecteur d'attribut Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_attribute_create(GKaitaiAttribute *attrib, GYamlNode *parent, bool need_id) +{ + bool result; /* Bilan à retourner */ + GYamlNode *node; /* Noeud particulier présent */ + const char *value; /* Valeur Yaml particulière */ + char *rebuilt_value; /* Valeur Yaml rassemblée */ + kaitai_scope_t fake; /* Contexte de circonstance */ + resolved_value_t bytes; /* Données brutes obtenues */ + GYamlNode *other_node; /* Autre noeud nécessaire */ + + result = false; + + /* Identifiant obligatoire */ + + node = g_yaml_node_find_first_by_path(parent, "/id"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + if (value == NULL) + { + g_object_unref(G_OBJECT(node)); + goto bad_id; + } + + attrib->raw_id = strdup(value); + + g_object_unref(G_OBJECT(node)); + + } + + else if (need_id) + goto bad_id; + + /* Identifiant facultatif */ + + node = g_yaml_node_find_first_by_path(parent, "/-orig-id"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + if (value == NULL) + { + g_object_unref(G_OBJECT(node)); + goto bad_id; + } + + attrib->orig_id = strdup(value); + + g_object_unref(G_OBJECT(node)); + + } + + /* Eventuelle documentation */ + + node = g_yaml_node_find_first_by_path(parent, "/doc"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + if (value == NULL) + { + g_object_unref(G_OBJECT(node)); + goto bad_doc; + } + + attrib->doc = strdup(value); + + g_object_unref(G_OBJECT(node)); + + } + + /* Champ contents */ + + node = g_yaml_node_find_first_by_path(parent, "/contents"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + rebuilt_value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node)); + + if (rebuilt_value == NULL) + { + g_object_unref(G_OBJECT(node)); + goto bad_content; + } + + fake.meta = NULL; + fake.root = NULL; + fake.parent = NULL; + fake.last = NULL; + + if (!resolve_kaitai_expression_as_bytes(&fake, rebuilt_value, strlen(rebuilt_value), &bytes)) + { + free(rebuilt_value); + g_object_unref(G_OBJECT(node)); + goto bad_content; + } + + free(rebuilt_value); + + attrib->fixed_content = bytes.bytes; + + g_object_unref(G_OBJECT(node)); + + attrib->payload |= KAP_FIXED_CONTENT; + + } + + /* Charge portée par un type */ + + node = g_yaml_node_find_first_by_path(parent, "/type"); + + if (node != NULL) + { + if (attrib->payload & KAP_FIXED_CONTENT) + { + printf("Can not handle fixed content and type definition at the same time for an attribute.\n"); + goto bad_definition; + } + + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + { + if (g_kaitai_attribute_resolve_bit_field(attrib, value)) + attrib->payload |= KAP_BIT_FIELD_TYPE; + + else if (g_kaitai_attribute_resolve_type(attrib, value)) + attrib->payload |= KAP_BASIC_TYPE; + + else + { + attrib->named_type = strdup(value); + attrib->payload |= KAP_USER_TYPE; + } + + } + + else + { + attrib->switchon = g_kaitai_switch_new(parent, attrib); + if (attrib->switchon == NULL) goto bad_definition; + + attrib->payload |= KAP_DYNAMIC_TYPE; + + } + + g_object_unref(G_OBJECT(node)); + + } + + /* Répétitions contrôlées ? */ + + node = g_yaml_node_find_first_by_path(parent, "/repeat"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + { + if (strcmp(value, "eos") == 0) + attrib->repetition = KAR_END_OF_STREAM; + + else if (strcmp(value, "expr") == 0) + { + other_node = g_yaml_node_find_first_by_path(parent, "/repeat-expr"); + + if (other_node != NULL) + { + if (G_IS_YAML_PAIR(other_node)) + { + value = g_yaml_pair_get_value(G_YAML_PAIR(other_node)); + + if (value != NULL) + { + attrib->repetition = KAR_EXPRESSION; + attrib->repeat_controller = strdup(value); + } + else + printf("Expected repeat expression\n"); + + } + + g_object_unref(G_OBJECT(other_node)); + + } + + } + + else if (strcmp(value, "until") == 0) + { + other_node = g_yaml_node_find_first_by_path(parent, "/repeat-until"); + + if (other_node != NULL) + { + assert(G_IS_YAML_PAIR(other_node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(other_node)); + + if (value != NULL) + { + attrib->repetition = KAR_UNTIL; + attrib->repeat_controller = strdup(value); + } + else + printf("Expected repeat expression\n"); + + } + + g_object_unref(G_OBJECT(other_node)); + + } + + } + + g_object_unref(G_OBJECT(node)); + + } + + /* Intégration sous condition ? */ + + node = g_yaml_node_find_first_by_path(parent, "/if"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + attrib->condition = strdup(value); + + g_object_unref(G_OBJECT(node)); + + } + + /* Taille fixée ? */ + + node = g_yaml_node_find_first_by_path(parent, "/size"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + { + attrib->fixed_size = strdup(value); + attrib->payload |= KAP_SIZED; + } + + g_object_unref(G_OBJECT(node)); + + if ((attrib->payload & KAP_SIZED) == 0) + goto bad_content; + + } + + /* Prise en considération d'une taille maximale */ + + node = g_yaml_node_find_first_by_path(parent, "/size-eos"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL && strcmp(value, "true") == 0) + { + if (attrib->payload != KAP_UNINITIALIZED) + /* printf warning */; + + attrib->payload |= KAP_SIZED_EOS; + + } + + g_object_unref(G_OBJECT(node)); + + } + + /* Champ terminator */ + + node = g_yaml_node_find_first_by_path(parent, "/terminator"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + rebuilt_value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node)); + + if (rebuilt_value == NULL) + { + g_object_unref(G_OBJECT(node)); + goto bad_content; + } + + fake.meta = NULL; + fake.root = NULL; + fake.parent = NULL; + fake.last = NULL; + + if (!resolve_kaitai_expression_as_bytes(&fake, rebuilt_value, strlen(rebuilt_value), &bytes)) + { + free(rebuilt_value); + g_object_unref(G_OBJECT(node)); + goto bad_content; + } + + free(rebuilt_value); + + if (attrib->terminator.data != NULL) + printf("A ending content has already been specified (implicitly by the strz type)"); + + else + { + attrib->terminator.data = bytes.bytes.data; + attrib->terminator.len = bytes.bytes.len; + } + + g_object_unref(G_OBJECT(node)); + + } + + /* Champ consume */ + + node = g_yaml_node_find_first_by_path(parent, "/consume"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + { + if (strcmp(value, "true") == 0) + attrib->consume = true; + + else if (strcmp(value, "false") == 0) + attrib->consume = false; + + else + printf("Unsupported value for the 'consume' property (expecting true of false)"); + + } + + g_object_unref(G_OBJECT(node)); + + } + + /* Champ include */ + + node = g_yaml_node_find_first_by_path(parent, "/include"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + { + if (strcmp(value, "true") == 0) + attrib->include = true; + + else if (strcmp(value, "false") == 0) + attrib->include = false; + + else + printf("Unsupported value for the 'include' property (expecting true of false)"); + + } + + g_object_unref(G_OBJECT(node)); + + } + + /* Champ eos-error */ + + node = g_yaml_node_find_first_by_path(parent, "/eos-error"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + { + if (strcmp(value, "true") == 0) + attrib->eos_error = true; + + if (strcmp(value, "false") == 0) + attrib->eos_error = false; + + else + printf("Unsupported value for the 'eos_error' property (expecting true of false)"); + + } + + g_object_unref(G_OBJECT(node)); + + } + + /* Validation finale */ + + result = g_kaitai_attribute_check(attrib); + + bad_definition: + + bad_doc: + bad_id: + bad_content: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = attribut Kaitai en cours de constitution. * +* desc = chaîne de caractère à interpréter en type. * +* * +* Description : Traduit en champ de bits une chaîne de caractères. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_attribute_resolve_bit_field(GKaitaiAttribute *attrib, const char *desc) +{ + bool result; /* Bilan à retourner */ + size_t len; /* Taille de la chaîne à lire */ + char *end; /* Prochain caractère à lire */ + unsigned long size; /* Taille du champ de bits */ + + result = false; + + if (desc[0] == 'b') + { + len = strlen(desc); + + size = strtoul(&desc[1], &end, 10); + + if (size > 64) + { + printf("Unsupported size for bit field: %lu\n", size); + goto exit; + } + + result = ((desc + len) == end); + + if (result) + attrib->bf_size = size; + + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = attribut Kaitai en cours de constitution. * +* desc = chaîne de caractère à interpréter en type. * +* * +* Description : Traduit en type concret une chaîne de caractères. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_attribute_resolve_type(GKaitaiAttribute *attrib, const char *desc) +{ + bool result; /* Bilan à retourner */ + + result = true; + + attrib->basic = BTP_INVALID; + attrib->has_endian = false; + + /** + * Cf. définition des types de base existants : + * http://doc.kaitai.io/user_guide.html#_fixed_size_structures + */ + +#define RESOLVE_ENDIAN \ + if (desc[2] == 'l') \ + { \ + if (desc[3] == 'e') \ + { \ + attrib->endian = SRE_LITTLE; \ + attrib->has_endian = true; \ + } \ + } \ + else if (desc[2] == 'b') \ + { \ + if (desc[3] == 'e') \ + { \ + attrib->endian = SRE_BIG; \ + attrib->has_endian = true; \ + } \ + } \ + + /* Analyse de la chaîne fournie */ + + switch (desc[0]) + { + case 'f': + switch (desc[1]) + { + case '4': + attrib->basic = BTP_754R_32; + RESOLVE_ENDIAN; + break; + + case '8': + attrib->basic = BTP_754R_64; + RESOLVE_ENDIAN; + break; + + default: + result = false; + break; + + } + break; + + case 's': + switch (desc[1]) + { + case '1': + attrib->basic = BTP_CHAR; + RESOLVE_ENDIAN; + break; + + case '2': + attrib->basic = BTP_SHORT; + RESOLVE_ENDIAN; + break; + + case '4': + attrib->basic = BTP_INT; + RESOLVE_ENDIAN; + break; + + case '8': + attrib->basic = BTP_LONG_LONG; + RESOLVE_ENDIAN; + break; + + case 't': + if (desc[2] == 'r') + { + attrib->basic = BTP_CHAR; + attrib->is_string = true; + if (desc[3] == 'z') + { + attrib->terminator.data = strdup(""); + attrib->terminator.len = 1; + } + } + else + result = false; + break; + + default: + result = false; + break; + + } + break; + + case 'u': + switch (desc[1]) + { + case '1': + attrib->basic = BTP_UCHAR; + RESOLVE_ENDIAN; + break; + + case '2': + attrib->basic = BTP_USHORT; + RESOLVE_ENDIAN; + break; + + case '4': + attrib->basic = BTP_UINT; + RESOLVE_ENDIAN; + break; + + case '8': + attrib->basic = BTP_ULONG_LONG; + RESOLVE_ENDIAN; + break; + + default: + result = false; + break; + + } + break; + + default: + result = false; + break; + + } + + /* Vérification d'une comparaison complète */ + if (result) + switch (attrib->basic) + { + case BTP_CHAR: + if (attrib->is_string) + { + if (attrib->terminator.data != NULL) + result = (desc[4] == 0); + else + result = (desc[3] == 0); + } + else + { + if (attrib->has_endian) + result = (desc[4] == 0); + else + result = (desc[2] == 0); + } + break; + + default: + if (attrib->has_endian) + result = (desc[4] == 0); + else + result = (desc[2] == 0); + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = attribut Kaitai à valider. * +* * +* Description : Valide la cohérence des informations portées par l'attribut. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_attribute_check(const GKaitaiAttribute *attrib) +{ + bool result; /* Bilan à retourner */ + + result = true; + + /** + * Une lecture de tous les octets restants ne doit correspondre qu'à des octets bruts. + */ + if (attrib->payload & KAP_SIZED_EOS && attrib->payload != KAP_SIZED_EOS) + { + result = (attrib->payload & KAP_BASIC_TYPE) && attrib->is_string; + + if (!result) + { + printf("Reading all the remaining bytes should only produce bytes."); + result = true; + } + + } + + /** + * Une chaîne (type str[z]) doit comporter une séquence de terminaison. + */ + if ((attrib->payload & KAP_BASIC_TYPE) && attrib->is_string) + { + result = (attrib->terminator.data != NULL) || (attrib->payload & (KAP_SIZED | KAP_SIZED_EOS)); + + if (!result) + { + printf("An unsized string (str type with no size attribute) has to be link to a terminator sequence."); + goto exit; + } + + } + + /** + * Si une séquence d'octets finaux est spécifiée, alors l'attribut + * doit correspondre à un type str[z] (lecture) ou de taille fixée + * (validation post-lecture). + */ + if (attrib->terminator.data != NULL) + { + result = ((attrib->payload & ~(KAP_FIXED_CONTENT | KAP_BASIC_TYPE | KAP_SIZED)) == 0); + + if (result && (attrib->payload & KAP_BASIC_TYPE)) + result = attrib->is_string; + + if (!result) + { + printf("A useless terminator is specified."); + result = true; + goto exit; + } + + } + + /** + * Il n'est pas possible d'inclure un marqueur de fin sans le consommer. + */ + if (!attrib->consume && attrib->include) + { + result = false; + printf("It is not possible to include a terminator without consuming it."); + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à dupliquer. * +* type = type utilisateur à associer au nouvel attribut. * +* * +* Description : Dérive un lecteur d'attribut Kaitai pour un type utilisateur.* +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiAttribute *g_kaitai_attribute_dup_for_user_type(const GKaitaiAttribute *attrib, const char *type) +{ + GKaitaiAttribute *result; /* Structure à retourner */ + + result = g_kaitai_attribute_dup_for(attrib); + + result->payload = KAP_USER_TYPE; + + result->named_type = strdup(type); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à dupliquer. * +* * +* Description : Copie le coeur de la définition d'un lecteur d'attribut. * +* * +* Retour : Nouvelle instance à compléter. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GKaitaiAttribute *g_kaitai_attribute_dup_for(const GKaitaiAttribute *attrib) +{ + GKaitaiAttribute *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_ATTRIBUTE, NULL); + + /** + * Il n'y a rien à copier dans la structure parente. + * + * Les travaux de copie ne portent ainsi que sur le présent attribut. + */ + + if (attrib->raw_id != NULL) + result->raw_id = strdup(attrib->raw_id); + + if (attrib->orig_id != NULL) + result->orig_id = strdup(attrib->orig_id); + + if (attrib->doc != NULL) + result->doc = strdup(attrib->doc); + + if (attrib->fixed_size != NULL) + result->fixed_size = strdup(attrib->fixed_size); + + result->repetition = attrib->repetition; + + if (attrib->repeat_controller != NULL) + result->repeat_controller = strdup(attrib->repeat_controller); + + if (attrib->condition != NULL) + result->condition = strdup(attrib->condition); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* * +* Description : Indique l'étiquette à utiliser pour identifier un attribut. * +* * +* Retour : Valeur brute de l'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_kaitai_attribute_get_label(const GKaitaiAttribute *attrib) +{ + const char *result; /* Valeur à renvoyer */ + GKaitaiAttributeClass *class; /* Classe de l'instance */ + + class = G_KAITAI_ATTRIBUTE_GET_CLASS(attrib); + + result = class->get_label(attrib); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* * +* Description : Indique la désignation brute d'un identifiant Kaitai. * +* * +* Retour : Valeur brute de l'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_kaitai_attribute_get_raw_id(const GKaitaiAttribute *attrib) +{ + char *result; /* Valeur à renvoyer */ + + result = attrib->raw_id; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* * +* Description : Indique la désignation originelle d'un identifiant Kaitai. * +* * +* Retour : Valeur originelle de l'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_kaitai_attribute_get_original_id(const GKaitaiAttribute *attrib) +{ + char *result; /* Valeur à renvoyer */ + + result = attrib->orig_id; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* * +* Description : Fournit une éventuelle documentation concernant l'attribut. * +* * +* Retour : Description enregistrée ou NULL si absente. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_kaitai_attribute_get_doc(const GKaitaiAttribute *attrib) +{ + char *result; /* Valeur à renvoyer */ + + result = attrib->doc; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* * +* Description : Indique la nature de la charge représentée par l'attribut. * +* * +* Retour : Forme de contenu représenté par le lecteur d'attribut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +KaitaiAttributePayload g_kaitai_attribute_get_payload(const GKaitaiAttribute *attrib) +{ + KaitaiAttributePayload result; /* Type de charge à renvoyer */ + + result = attrib->payload; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* basic = type de base Kaitai reconnu par le lecteur. [OUT]* +* is_string = nature du type BTP_CHAR en sortie. [OUT] * +* * +* Description : Précise un éventuel type de base reconnu par le lecteur. * +* * +* Retour : Validité du type renseigné en argument. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_attribute_get_basic_type(const GKaitaiAttribute *attrib, BaseType *basic, bool *is_string) +{ + bool result; /* Validité à retourner */ + + result = (attrib->payload & KAP_BASIC_TYPE); + + if (result) + { + *basic = attrib->basic; + *is_string = attrib->is_string; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* content = contenu binaire à venir lire. * +* range = espace disponible pour la lecture. * +* out = tableau d'octets retournés. [OUT] * +* len = taille de ce tableau alloué. [OUT] * +* * +* Description : Lit les octets d'une chaîne représentée. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_attribute_read_truncated_bytes(const GKaitaiAttribute *attrib, const GBinContent *content, const mrange_t *range, bin_t **out, size_t *len) +{ + bool result; /* Bilan à retourner */ + vmpa2t tmppos; /* Localisation modifiable */ + const bin_t *data; /* Accès aux données brutes */ + + result = false; + + if ((attrib->payload & KAP_SIZED) == 0) + goto bad_type; + + copy_vmpa(&tmppos, get_mrange_addr(range)); + + *len = get_mrange_length(range); + + data = g_binary_content_get_raw_access(content, &tmppos, *len); + + *out = malloc(sizeof(bin_t) * (*len + 1)); + + memcpy(*out, data, *len); + (*out)[*len] = '\0'; + + result = true; + + bad_type: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* * +* Description : Détermine si l'attribue porte une valeur entière signée. * +* * +* Retour : Bilan de la consultation : true si un entier signé est visé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_attribute_handle_signed_integer(const GKaitaiAttribute *attrib) +{ + bool result; /* Bilan à retourner */ + + result = false; + + if ((attrib->payload & KAP_BASIC_TYPE) == 0) + goto bad_type; + + switch (attrib->basic) + { + case BTP_CHAR: + case BTP_SHORT: + case BTP_INT: + case BTP_LONG_LONG: + result = true; + break; + + default: + break; + + } + + bad_type: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* content = contenu binaire à venir lire. * +* range = espace de lecture. * +* endian = boustime des données à respecter. * +* out = valeur à sauvegarder sous une forme générique.[OUT]* +* * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_attribute_read_value(const GKaitaiAttribute *attrib, const GBinContent *content, const mrange_t *range, SourceEndian endian, resolved_value_t *out) +{ + bool result; /* Bilan à retourner */ + vmpa2t tmppos; /* Localisation modifiable */ + const bin_t *data; /* Données brutes restituées */ + int8_t stmp8; /* Valeur de 8 bits lue */ + uint8_t tmp8; /* Valeur de 8 bits lue */ + int16_t stmp16; /* Valeur de 16 bits lue */ + uint16_t tmp16; /* Valeur de 16 bits lue */ + int32_t stmp32; /* Valeur de 32 bits lue */ + uint32_t tmp32; /* Valeur de 32 bits lue */ + int64_t stmp64; /* Valeur de 64 bits lue */ + uint64_t tmp64; /* Valeur de 64 bits lue */ + + result = false; + + if (attrib->payload & (KAP_FIXED_CONTENT | KAP_SIZED | KAP_SIZED_EOS)) + { + copy_vmpa(&tmppos, get_mrange_addr(range)); + + data = g_binary_content_get_raw_access(content, &tmppos, get_mrange_length(range)); + result = (data != NULL); + + if (result) + { + out->type = GVT_BYTES; + + out->bytes.len = get_mrange_length(range); + + out->bytes.data = malloc(out->bytes.len); + memcpy(out->bytes.data, data, out->bytes.len); + + } + + } + + else if (attrib->payload & KAP_BASIC_TYPE) + { + copy_vmpa(&tmppos, get_mrange_addr(range)); + + switch (attrib->basic) + { + case BTP_CHAR: + if (attrib->is_string) + { + copy_vmpa(&tmppos, get_mrange_addr(range)); + + data = g_binary_content_get_raw_access(content, &tmppos, get_mrange_length(range)); + result = (data != NULL); + + if (result) + { + out->type = GVT_BYTES; + + out->bytes.len = get_mrange_length(range); + + out->bytes.data = malloc(out->bytes.len); + memcpy(out->bytes.data, data, out->bytes.len); + + } + + } + else + { + assert(get_mrange_length(range) == 1); + result = g_binary_content_read_s8(content, &tmppos, &stmp8); + out->type = GVT_SIGNED_INTEGER; + out->signed_integer = stmp8; + } + break; + + case BTP_UCHAR: + assert(get_mrange_length(range) == 1); + result = g_binary_content_read_u8(content, &tmppos, &tmp8); + out->type = GVT_UNSIGNED_INTEGER; + out->unsigned_integer = tmp8; + break; + + case BTP_SHORT: + assert(get_mrange_length(range) == 2); + result = g_binary_content_read_s16(content, &tmppos, endian, &stmp16); + out->type = GVT_SIGNED_INTEGER; + out->signed_integer = stmp16; + break; + + case BTP_USHORT: + assert(get_mrange_length(range) == 2); + result = g_binary_content_read_u16(content, &tmppos, endian, &tmp16); + out->type = GVT_UNSIGNED_INTEGER; + out->unsigned_integer = tmp16; + break; + + case BTP_INT: + assert(get_mrange_length(range) == 4); + result = g_binary_content_read_s32(content, &tmppos, endian, &stmp32); + out->type = GVT_SIGNED_INTEGER; + out->signed_integer = stmp32; + break; + + case BTP_UINT: + assert(get_mrange_length(range) == 4); + result = g_binary_content_read_u32(content, &tmppos, endian, &tmp32); + out->type = GVT_UNSIGNED_INTEGER; + out->unsigned_integer = tmp32; + break; + + case BTP_LONG_LONG: + assert(get_mrange_length(range) == 8); + result = g_binary_content_read_s64(content, &tmppos, endian, &stmp64); + out->type = GVT_SIGNED_INTEGER; + out->signed_integer = stmp64; + break; + + case BTP_ULONG_LONG: + assert(get_mrange_length(range) == 8); + result = g_binary_content_read_u64(content, &tmppos, endian, &tmp64); + out->type = GVT_UNSIGNED_INTEGER; + out->unsigned_integer = tmp64; + break; + + default: + break; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. * +* content = contenu binaire à venir lire. * +* epos = tête de lecture avec granularité en bits. * +* size = quantité de bits à prendre en compte. * +* endian = boustime des données à respecter. * +* out = valeur à sauvegarder sous une forme générique.[OUT]* +* * +* Description : Lit la valeur d'un champ de bits Kaitai représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_attribute_read_bit_field_value(const GKaitaiAttribute *attrib, const GBinContent *content, const ext_vmpa_t *epos, uint8_t size, SourceEndian endian, resolved_value_t *out) +{ + bool result; /* Bilan à retourner */ + ext_vmpa_t tmpepos; /* Localisation modifiable */ + uint64_t tmp64; /* Valeur de 64 bits lue */ + + result = false; + + if (attrib->payload & KAP_BIT_FIELD_TYPE) + { + copy_evmpa(&tmpepos, epos); + + result = g_binary_content_read_bits(content, &tmpepos, size, endian, &tmp64); + + if (result) + { + out->type = GVT_UNSIGNED_INTEGER; + out->unsigned_integer = tmp64; + } + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : attrib = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* epos = tête de lecture courante. [OUT] * +* record = noeud d'arborescence d'éléments rencontrés. [OUT] * +* * +* Description : Parcourt un contenu binaire selon des spécifications Kaitai. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record) +{ + bool result; /* Bilan à retourner */ + resolved_value_t authorized; /* Validation des traitements */ + + mrange_t work_range; /* Définition de cette aire */ + GBinContent *work_area; /* Aire de travail */ + bool has_empty_size; /* Mémorise une taille nulle */ + + + //unsigned long long value; /* Valeur entière finale */ + //bool status; /* Bilan d'une conversion */ + + + vmpa2t tmp; /* Position de travail */ + phys_t diff; /* Différentiel de positions */ + resolved_value_t resolved; /* Valeur entière obtenue */ + phys_t max_size; /* Taille maximale imposée */ + + + const bin_t *data; /* Données à comparer */ + GKaitaiType *user_type; /* Définition particulière */ + + + mrange_t range; /* Couverture appliquée */ + SourceEndian endian; /* Boutisme à observer */ + phys_t cur_diff; /* Avancée de lecture courante */ + + + result = false; + *record = NULL; + + /* Lecture soumise à condition ? */ + + if (attrib->condition != NULL) + { + result = resolve_kaitai_expression_as_boolean(locals, + attrib->condition, + strlen(attrib->condition), + &authorized); + + if (!result || !authorized.status) + goto exit; + + } + + /* Zone de travail restreinte */ + + g_binary_content_compute_end_pos(content, &tmp); + diff = compute_vmpa_diff(&epos->base, &tmp); + + if (epos->consumed_extra_bits > 0 && diff > 0) + diff--; + + if (attrib->payload & KAP_SIZED) + { + result = resolve_kaitai_expression_as_integer(locals, + attrib->fixed_size, + strlen(attrib->fixed_size), + &resolved); + + if (result) + { + if (resolved.type == GVT_UNSIGNED_INTEGER) + max_size = resolved.unsigned_integer; + else + { + assert(resolved.type == GVT_SIGNED_INTEGER); + + if (resolved.signed_integer < 0) + result = false; + else + max_size = resolved.signed_integer; + + } + + if (result) + result = (diff >= max_size); + + if (!result) + printf("Need more data!\n"); + + if (result && max_size < diff) + diff = max_size; + + } + + if (!result) + goto exit; + + align_evmpa_on_byte(epos); + + init_mrange(&work_range, &epos->base, diff); + work_area = g_restricted_content_new(content, &work_range); + + has_empty_size = (diff == 0); + + } + else + { + work_area = content; + has_empty_size = false; + } + + /* Etablissement d'une zone de correspondance */ + + if (attrib->payload == KAP_UNINITIALIZED) + assert(false); + + else if (attrib->payload & KAP_SIZED_EOS) + { + align_evmpa_on_byte(epos); + result = true; + } + + else if (attrib->payload & KAP_FIXED_CONTENT) + { + if (diff >= attrib->fixed_content.len) + { + align_evmpa_on_byte(epos); + + copy_vmpa(&tmp, &epos->base); + + data = g_binary_content_get_raw_access(work_area, &tmp, attrib->fixed_content.len); + assert(data != NULL); + + result = (memcmp(data, attrib->fixed_content.data, attrib->fixed_content.len) == 0); + + if (result) + diff = attrib->fixed_content.len; + + } + + } + + else if (attrib->payload & KAP_BIT_FIELD_TYPE) + { + if (attrib->has_endian) + endian = attrib->endian; + else + endian = g_kaitai_meta_get_endian(locals->meta); + + *record = g_record_bit_field_new(attrib, work_area, epos, attrib->bf_size, endian); + + result = (*record != NULL); + + if (result) + advance_evmpa_bits(epos, attrib->bf_size); + + } + + else if (attrib->payload & KAP_BASIC_TYPE) + { + align_evmpa_on_byte(epos); + + switch (attrib->basic) + { + case BTP_CHAR: + case BTP_UCHAR: + if (attrib->is_string) + { + if ((attrib->payload & KAP_SIZED) == 0) + result = g_kaitai_attribute_parse_terminated_bytes(attrib, locals, + work_area, &epos->base, record); + } + else + { + result = (diff >= 1); + diff = 1; + } + break; + + case BTP_SHORT: + case BTP_USHORT: + result = (diff >= 2); + diff = 2; + break; + + case BTP_INT: + case BTP_UINT: + case BTP_754R_32: + result = (diff >= 4); + diff = 4; + break; + + case BTP_LONG_LONG: + case BTP_ULONG_LONG: + case BTP_754R_64: + result = (diff >= 8); + diff = 8; + break; + + default: + break; + + } + + } + + else if (attrib->payload & KAP_USER_TYPE) + { + user_type = find_sub_type(locals, attrib->named_type); + + if (user_type != NULL) + { + result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(user_type), + locals, work_area, epos, record); + + if (result) + /** + * Le type utilisateur dérive du type GKaitaiStruct, qui ne possède pas + * d'identifiant propre. La correspondance produite est ainsi nominalement + * anonyme, ce qui empêche toute résolution. + * + * Le rattachement de l'étiquette de l'attribut d'origine est donc forcée ici. + */ + g_match_record_fix_creator(*record, G_KAITAI_PARSER(attrib)); + + + g_object_unref(G_OBJECT(user_type)); + + } + + } + + else if (attrib->payload & KAP_DYNAMIC_TYPE) + result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib->switchon), locals, work_area, epos, record); + + else if (attrib->payload & KAP_SIZED) + { + /* Cas déjà traité en début de fonction */ + + } + + /* Enregistrement de la correspondance */ + + if (result && *record == NULL) + { + /** + * A ce stade, la granularité des travaux est l'octet. + */ + assert(epos->consumed_extra_bits == 0); + + /** + * On choisit de laisser la création de correspondances nulles. + * + * Cela permet de disposer de la présence de champs valides, même vides + * (cf. "4.10.3. Repeat until condition is met") + */ + + /* if (diff > 0) */ + { + result = g_kaitai_attribute_compute_maybe_terminated_range(attrib, locals, content, + &epos->base, &diff, &range); + + if (result) + { + if (has_empty_size) + *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(attrib), content, &epos->base)); + + else + { + if (attrib->has_endian) + endian = attrib->endian; + else + endian = g_kaitai_meta_get_endian(locals->meta); + + *record = G_MATCH_RECORD(g_record_item_new(attrib, work_area, &range, endian)); + + if (*record != NULL) + advance_vmpa(&epos->base, diff); + else + result = false; + + } + + } + + } + + } + + /* Libération de zone de travail restreinte ? */ + + if (attrib->payload & KAP_SIZED) + { + /* Réalignement éventuel suite aux lectures dans la zone périmétrée... */ + align_evmpa_on_byte(epos); + + cur_diff = compute_vmpa_diff(get_mrange_addr(&work_range), &epos->base); + + /* Pour GCC... */ + max_size = get_mrange_length(&work_range); + + if (cur_diff < max_size) + advance_vmpa(&epos->base, max_size - cur_diff); + + assert(work_area != content); + g_object_unref(G_OBJECT(work_area)); + + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* pos = tête de lecture courante. [OUT] * +* record = noeud d'arborescence d'éléments rencontrés. [OUT] * +* * +* Description : Extrait d'un contenu une série d'octets avec terminaison. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_attribute_parse_terminated_bytes(GKaitaiAttribute *attrib, const kaitai_scope_t *locals, GBinContent *content, vmpa2t *pos, GMatchRecord **record) +{ + bool result; /* Bilan à retourner */ + sized_string_t marker; /* Marqueur potentiel à tester */ + vmpa2t iter; /* Tête de lecture courante */ + vmpa2t end; /* Fin du parcours possible */ + vmpa2t tmp; /* Position à mouvante */ + phys_t diff; /* Avancée de lecture courante */ + mrange_t range; /* Couverture appliquée */ + SourceEndian endian; /* Boutisme à observer */ + + result = false; + + /* Recherche du marqueur de fin */ + + marker.len = attrib->terminator.len; + + copy_vmpa(&iter, pos); + g_binary_content_compute_end_pos(content, &end); + + while (cmp_vmpa_by_phy(&iter, &end) < 0) + { + copy_vmpa(&tmp, &iter); + + marker.data = (char *)g_binary_content_get_raw_access(content, &tmp, marker.len); + if (marker.data == NULL) break; + + if (szmemcmp(&marker, &attrib->terminator) == 0) + { + result = true; + break; + } + + advance_vmpa(&iter, 1); + + } + + /* Si la recherche a abouti */ + + if (result) + { + diff = compute_vmpa_diff(pos, &iter); + + if (attrib->include) + diff += marker.len; + + init_mrange(&range, pos, diff); + + if (attrib->has_endian) + endian = attrib->endian; + else + endian = g_kaitai_meta_get_endian(locals->meta); + + *record = G_MATCH_RECORD(g_record_item_new(attrib, content, &range, endian)); + + copy_vmpa(pos, &iter); + + if (attrib->consume) + advance_vmpa(pos, marker.len); + + } + + /* Sinon l'absence de marqueur est-elle tolérée ? */ + + else if (!attrib->eos_error) + { + diff = compute_vmpa_diff(pos, &end); + + init_mrange(&range, pos, diff); + + if (attrib->has_endian) + endian = attrib->endian; + else + endian = g_kaitai_meta_get_endian(locals->meta); + + *record = G_MATCH_RECORD(g_record_item_new(attrib, content, &range, endian)); + + copy_vmpa(pos, &end); + + result = true; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* pos = tête de lecture courante. * +* maxsize = taille maximale de la zone de correspondance. [OUT]* +* range = zone de couverture à officialiser. [OUT] * +* * +* Description : Détermine la zone de couverture finale d'une correspondance. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttribute *attrib, const kaitai_scope_t *locals, const GBinContent *content, const vmpa2t *pos, phys_t *maxsize, mrange_t *range) +{ + bool result; /* Bilan à retourner */ + sized_string_t marker; /* Marqueur potentiel à tester */ + vmpa2t iter; /* Tête de lecture courante */ + vmpa2t end; /* Fin du parcours possible */ + vmpa2t tmp; /* Position à mouvante */ + phys_t diff; /* Avancée de lecture courante */ + + if (attrib->terminator.data == NULL) + { + init_mrange(range, pos, *maxsize); + result = true; + } + + else + { + result = false; + + if (attrib->terminator.len > *maxsize) + goto exit; + + /* Recherche du marqueur de fin */ + + marker.len = attrib->terminator.len; + + copy_vmpa(&iter, pos); + + copy_vmpa(&tmp, pos); + advance_vmpa(&tmp, *maxsize - marker.len); + + while (cmp_vmpa_by_phy(&iter, &end) <= 0) + { + copy_vmpa(&tmp, &iter); + + marker.data = (char *)g_binary_content_get_raw_access(content, &tmp, marker.len); + if (marker.data == NULL) break; + + if (szmemcmp(&marker, &attrib->terminator) == 0) + { + result = true; + break; + } + + advance_vmpa(&iter, 1); + + } + + /* Si la recherche a abouti */ + + if (result) + { + diff = compute_vmpa_diff(pos, &iter); + + if (attrib->include) + init_mrange(range, pos, diff + marker.len); + else + init_mrange(range, pos, diff); + + assert((diff + marker.len) <= *maxsize); + + if (attrib->consume) + *maxsize = diff + marker.len; + else + *maxsize = diff; + + } + + /* Sinon l'absence de marqueur est-elle tolérée ? */ + + else if (!attrib->eos_error) + { + init_mrange(range, pos, *maxsize); + result = true; + } + + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* epos = tête de lecture courante. [OUT] * +* record = noeud d'arborescence d'éléments rencontrés. [OUT] * +* * +* Description : Parcourt un contenu binaire selon des spécifications Kaitai. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record) +{ + bool result; /* Bilan à retourner */ + resolved_value_t authorized; /* Validation des traitements */ + GRecordList *list; /* Constitution d'une liste */ + vmpa2t end; /* Position maximale du flux */ + phys_t diff; /* Différentiel de positions */ + GMatchRecord *child; /* Element de liste à intégrer */ + resolved_value_t resolved; /* Valeur entière obtenue */ + unsigned long long count; /* Nombre d'itérations à mener */ + unsigned long long i; /* Boucle de parcours */ + resolved_value_t loop; /* Poursuite des lectures ? */ + + if (attrib->repetition == KAR_NO_REPETITION) + result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, record); + + else + { + /* Lecture soumise à condition ? */ + + if (attrib->condition != NULL) + { + result = resolve_kaitai_expression_as_boolean(locals, + attrib->condition, + strlen(attrib->condition), + &authorized); + + if (!result || !authorized.status) + goto exit; + + } + + list = g_record_list_new(attrib, content, &epos->base); + + switch (attrib->repetition) + { + case KAR_END_OF_STREAM: + + result = true; + + g_binary_content_compute_end_pos(content, &end); + diff = compute_vmpa_diff(&epos->base, &end); + + while (diff > 0) + { + result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child); + if (!result) break; + + g_record_list_add_record(list, child); + remember_last_record(locals, child); + + diff = compute_vmpa_diff(&epos->base, &end); + + } + + break; + + case KAR_EXPRESSION: + + result = resolve_kaitai_expression_as_integer(locals, + attrib->repeat_controller, + strlen(attrib->repeat_controller), + &resolved); + + if (resolved.type == GVT_UNSIGNED_INTEGER) + count = resolved.unsigned_integer; + else + { + assert(resolved.type == GVT_SIGNED_INTEGER); + + if (resolved.signed_integer < 0) + { + result = false; + break; + } + + count = resolved.signed_integer; + + } + + for (i = 0; i < count; i++) + { + result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child); + if (!result) break; + + g_record_list_add_record(list, child); + remember_last_record(locals, child); + + } + + break; + + case KAR_UNTIL: + + do + { + result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child); + if (!result) break; + + g_record_list_add_record(list, child); + remember_last_record(locals, child); + + result = resolve_kaitai_expression_as_boolean(locals, + attrib->repeat_controller, + strlen(attrib->repeat_controller), + &loop); + if (!result) break; + + } + while (!loop.status); + + break; + + default: + break; + + } + + if (!result) g_clear_object(&list); + + *record = G_MATCH_RECORD(list); + + } + + exit: + + return result; + +} diff --git a/plugins/kaitai/parsers/attribute.h b/plugins/kaitai/parsers/attribute.h new file mode 100644 index 0000000..9b43936 --- /dev/null +++ b/plugins/kaitai/parsers/attribute.h @@ -0,0 +1,158 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * attribute.h - prototypes pour la spécification d'un attribut Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H +#define _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include <analysis/content.h> +#include <analysis/types/basic.h> +#include <plugins/yaml/node.h> + + +#include "../expression.h" + + + +#define G_TYPE_KAITAI_ATTRIBUTE g_kaitai_attribute_get_type() +#define G_KAITAI_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttribute)) +#define G_IS_KAITAI_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ATTRIBUTE)) +#define G_KAITAI_ATTRIBUTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttributeClass)) +#define G_IS_KAITAI_ATTRIBUTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ATTRIBUTE)) +#define G_KAITAI_ATTRIBUTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttributeClass)) + + +/* Spécification d'un attribut Kaitai (instance) */ +typedef struct _GKaitaiAttribute GKaitaiAttribute; + +/* Spécification d'un attribut Kaitai (classe) */ +typedef struct _GKaitaiAttributeClass GKaitaiAttributeClass; + + +/* Type de charge associée à un attribut */ +typedef enum _KaitaiAttributePayload +{ + KAP_UNINITIALIZED = (0 << 0), /* Type non initialisé */ + + KAP_FIXED_CONTENT = (1 << 0), /* Contenu brut attendu */ + KAP_BIT_FIELD_TYPE = (1 << 1), /* Champ d'un ou plusieurs bits*/ + KAP_BASIC_TYPE = (1 << 2), /* Type prédéfini */ + KAP_USER_TYPE = (1 << 3), /* Type personnalisé */ + KAP_DYNAMIC_TYPE = (1 << 4), /* Type dynmatique */ + KAP_SIZED = (1 << 5), /* Bourrage dimensionné */ + KAP_SIZED_EOS = (1 << 6), /* Bourrage final */ + +} KaitaiAttributePayload; + +/* Types de base reconnus par Kaitai */ /* TODO : REMME ? (car non utilisé) */ +typedef enum _KaitaiBasicType +{ + KBT_U1, /* Octet non signé */ + KBT_U2, /* Mot de 16 bits non signé */ + KBT_U2LE, /* Mot de 16 bits non signé */ + KBT_U2BE, /* Mot de 16 bits non signé */ + KBT_U4, /* Mot de 32 bits non signé */ + KBT_U4LE, /* Mot de 32 bits non signé */ + KBT_U4BE, /* Mot de 32 bits non signé */ + KBT_U8, /* Mot de 64 bits non signé */ + KBT_U8LE, /* Mot de 64 bits non signé */ + KBT_U8BE, /* Mot de 64 bits non signé */ + KBT_S1, /* Octet signé */ + KBT_S2, /* Mot de 16 bits signé */ + KBT_S2LE, /* Mot de 16 bits signé */ + KBT_S2BE, /* Mot de 16 bits signé */ + KBT_S4, /* Mot de 32 bits signé */ + KBT_S4LE, /* Mot de 32 bits signé */ + KBT_S4BE, /* Mot de 32 bits signé */ + KBT_S8, /* Mot de 64 bits signé */ + KBT_S8LE, /* Mot de 64 bits signé */ + KBT_S8BE, /* Mot de 64 bits signé */ + KBT_F4, /* Flottant sur 32 bits */ + KBT_F4BE, /* Flottant sur 32 bits */ + KBT_F4LE, /* Flottant sur 32 bits */ + KBT_F8, /* Flottant sur 64 bits */ + KBT_F8BE, /* Flottant sur 64 bits */ + KBT_F8LE, /* Flottant sur 64 bits */ + KBT_STR, /* Chaîne de caractères */ + KBT_STRZ, /* Chaîne de caractères + '\0' */ + +} KaitaiBasicType; + +/* Formes de répétition d'une lecture d'attribut */ +typedef enum _KaitaiAttributeRepetition +{ + KAR_NO_REPETITION, /* Aucune forme de répétition */ + + KAR_END_OF_STREAM, /* Redites autant que possible */ + KAR_EXPRESSION, /* Répétitions selon quantité */ + KAR_UNTIL, /* Répétitions sous condition */ + +} KaitaiAttributeRepetition; + + +/* Indique le type défini pour un attribut de la spécification Kaitai. */ +GType g_kaitai_attribute_get_type(void); + +/* Construit un lecteur d'attribut Kaitai. */ +GKaitaiAttribute *g_kaitai_attribute_new(GYamlNode *); + +/* Dérive un lecteur d'attribut Kaitai pour un type utilisateur. */ +GKaitaiAttribute *g_kaitai_attribute_dup_for_user_type(const GKaitaiAttribute *, const char *); + +/* Indique l'étiquette à utiliser pour identifier un attribut. */ +const char *g_kaitai_attribute_get_label(const GKaitaiAttribute *); + +/* Indique la désignation brute d'un identifiant Kaitai. */ +const char *g_kaitai_attribute_get_raw_id(const GKaitaiAttribute *); + +/* Indique la désignation originelle d'un identifiant Kaitai. */ +const char *g_kaitai_attribute_get_original_id(const GKaitaiAttribute *); + +/* Fournit une éventuelle documentation concernant l'attribut. */ +const char *g_kaitai_attribute_get_doc(const GKaitaiAttribute *); + +/* Indique la nature de la charge représentée par l'attribut. */ +KaitaiAttributePayload g_kaitai_attribute_get_payload(const GKaitaiAttribute *); + +/* Précise un éventuel type de base reconnu par le lecteur. */ +bool g_kaitai_attribute_get_basic_type(const GKaitaiAttribute *, BaseType *, bool *); + +/* Lit les octets d'une chaîne représentée. */ +bool g_kaitai_attribute_read_truncated_bytes(const GKaitaiAttribute *, const GBinContent *, const mrange_t *, bin_t **, size_t *); + +/* Détermine si l'attribue porte une valeur entière signée. */ +bool g_kaitai_attribute_handle_signed_integer(const GKaitaiAttribute *); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +bool g_kaitai_attribute_read_value(const GKaitaiAttribute *, const GBinContent *, const mrange_t *, SourceEndian, resolved_value_t *); + +/* Lit la valeur d'un champ de bits Kaitai représenté. */ +bool g_kaitai_attribute_read_bit_field_value(const GKaitaiAttribute *, const GBinContent *, const ext_vmpa_t *, uint8_t, SourceEndian, resolved_value_t *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H */ diff --git a/plugins/kaitai/parsers/enum-int.h b/plugins/kaitai/parsers/enum-int.h new file mode 100644 index 0000000..b62ae41 --- /dev/null +++ b/plugins/kaitai/parsers/enum-int.h @@ -0,0 +1,79 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enum-int.h - prototypes internes pour la gestion des énumérations Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_PARSERS_ENUM_INT_H +#define PLUGINS_KAITAI_PARSERS_ENUM_INT_H + + +#include "enum.h" + + + +/* ------------------------- MANIPULATION D'UNE ENUMERATION ------------------------- */ + + +/* Mémorisation d'une valeur d'énumération */ +typedef struct _enum_value_t +{ + resolved_value_t value; /* Valeur entière représentée */ + char *label; /* Elément associé à une valeur*/ + char *doc; /* Eventuelle documentation */ + +} enum_value_t; + + + +/* ----------------------- GESTION D'UN GROUPE D'ENUMERATIONS ----------------------- */ + + +/* Définition d'un ensemble d'énumérations Kaitai (instance) */ +struct _GKaitaiEnum +{ + GObject parent; /* A laisser en premier */ + + char *name; /* Désignation de l'énumération*/ + + enum_value_t **cases_v2l; /* Choix indexés par valeur */ + size_t cases_v2l_count; /* Quantité de ces choix */ + + enum_value_t **cases_l2v; /* Choix indexés par étiquette */ + size_t cases_l2v_count; /* Quantité de ces choix */ + + enum_value_t *defcase; /* Choix par défaut ou NULL */ + +}; + +/* Définition d'un ensemble d'énumérations Kaitai (classe) */ +struct _GKaitaiEnumClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un groupe d'énumérations Kaitai. */ +bool g_kaitai_enum_create(GKaitaiEnum *, GYamlNode *); + + + +#endif /* PLUGINS_KAITAI_PARSERS_ENUM_INT_H */ diff --git a/plugins/kaitai/parsers/enum.c b/plugins/kaitai/parsers/enum.c new file mode 100644 index 0000000..27e5660 --- /dev/null +++ b/plugins/kaitai/parsers/enum.c @@ -0,0 +1,765 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enum.h - gestion des énumérations Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "enum.h" + + +#include <malloc.h> +#include <string.h> + + +#include <i18n.h> + + +#include <common/extstr.h> +#include <common/sort.h> +#include <core/logs.h> +#include <plugins/yaml/collection.h> +#include <plugins/yaml/pair.h> + + +#include "enum-int.h" + + + +/* ------------------------- MANIPULATION D'UNE ENUMERATION ------------------------- */ + + +/* Construit une valeur d'énumération à partir d'indications. */ +static enum_value_t *build_enum_value(GYamlNode *, bool *); + +/* Supprime de la mémoire une valeur d'énumération. */ +static void delete_enum_value(enum_value_t *); + +/* Etablit la comparaison entre deux valeurs d'énumération. */ +static int compare_enum_values_by_value(const enum_value_t **, const enum_value_t **); + +/* Etablit la comparaison entre deux noms d'énumération. */ +static int compare_enum_values_by_label(const enum_value_t **, const enum_value_t **); + +/* Etablit la comparaison entre deux noms d'énumération. */ +static int compare_enum_values_by_sized_label(const sized_string_t *, const enum_value_t **); + + + +/* ----------------------- GESTION D'UN GROUPE D'ENUMERATIONS ----------------------- */ + + +/* Initialise la classe des groupes d'énumérations Kaitai. */ +static void g_kaitai_enum_class_init(GKaitaiEnumClass *); + +/* Initialise un groupe d'énumérations Kaitai. */ +static void g_kaitai_enum_init(GKaitaiEnum *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_enum_dispose(GKaitaiEnum *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_enum_finalize(GKaitaiEnum *); + + + +/* ---------------------------------------------------------------------------------- */ +/* MANIPULATION D'UNE ENUMERATION */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = noeud Yaml à venir lire. * +* defcase = indique si une valeur par défaut est visée. [OUT] * +* * +* Description : Construit une valeur d'énumération à partir d'indications. * +* * +* Retour : Structure de valeur mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static enum_value_t *build_enum_value(GYamlNode *node, bool *defcase) +{ + enum_value_t *result; /* Valeur à retourner */ + const char *key; /* Clef d'une énumération */ + kaitai_scope_t fake; /* Contexte de circonstance */ + resolved_value_t kval; /* Valeur à indexer */ + const char *value; /* Valeur Yaml particulière */ + char *path; /* Chemin d'accès suivant */ + GYamlNode *children; /* Sous-noeuds rattachés */ + GYamlNode *sub; /* Sous-noeud à considérer */ + + result = NULL; + + *defcase = false; + + if (!G_IS_YAML_PAIR(node)) + goto bad_node; + + /* Identification de la valeur énumérative */ + + key = g_yaml_pair_get_key(G_YAML_PAIR(node)); + + if (strcmp(key, "_") == 0) + { + /** + * Exemple de choix par défaut : + * http://doc.kaitai.io/user_guide.html#tlv + */ + + kval.type = GVT_UNSIGNED_INTEGER; + kval.unsigned_integer = ~0llu; + + *defcase = true; + + } + + else + { + fake.meta = NULL; + fake.root = NULL; + fake.parent = NULL; + fake.last = NULL; + + if (!resolve_kaitai_expression_as_integer(&fake, key, strlen(key), &kval)) + goto bad_node; + + } + + /* Récupération des éléments associés à la valeur */ + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value != NULL) + { + result = malloc(sizeof(enum_value_t)); + + result->value = kval; + result->label = strdup(value); + result->doc = NULL; + + } + else + { + /** + * Les énumérations peuvent comporter un commentaire associé + * sous forme d'un élément de documentation complémentaire. + * + * Cf. http://doc.kaitai.io/user_guide.html#verbose-enums + */ + + asprintf(&path, "/%s/", key); + children = g_yaml_node_find_first_by_path(node, path); + free(path); + + if (!G_IS_YAML_COLLEC(children)) + goto bad_value; + + /* Identifiant */ + + sub = g_yaml_node_find_first_by_path(children, "/id"); + + if (!G_IS_YAML_PAIR(sub)) + goto bad_sub_value; + + value = g_yaml_pair_get_value(G_YAML_PAIR(sub)); + + if (value == NULL) + goto bad_sub_value; + + result = malloc(sizeof(enum_value_t)); + + result->value = kval; + result->label = strdup(value); + result->doc = NULL; + + g_object_unref(G_OBJECT(sub)); + + /* Documentation */ + + sub = g_yaml_node_find_first_by_path(children, "/doc"); + + if (!G_IS_YAML_PAIR(sub)) + goto bad_sub_value; + + value = g_yaml_pair_get_value(G_YAML_PAIR(sub)); + + if (value == NULL) + goto bad_sub_value; + + result->doc = strdup(value); + + bad_sub_value: + + g_clear_object(&sub); + + g_object_unref(G_OBJECT(children)); + + bad_value: + + ; + + } + + bad_node: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : value = valeur à traiter. * +* * +* Description : Supprime de la mémoire une valeur d'énumération. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void delete_enum_value(enum_value_t *value) +{ + EXIT_RESOLVED_VALUE(value->value); + + free(value->label); + + if (value->doc != NULL) + free(value->doc); + + free(value); + +} + + +/****************************************************************************** +* * +* Paramètres : a = premières informations à consulter. * +* b = secondes informations à consulter. * +* * +* Description : Etablit la comparaison entre deux valeurs d'énumération. * +* * +* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int compare_enum_values_by_value(const enum_value_t **a, const enum_value_t **b) +{ + int result; /* Bilan à retourner */ + const resolved_value_t *value_a; /* Raccouri d'accès pour a */ + const resolved_value_t *value_b; /* Raccouri d'accès pour b */ + + value_a = &(*a)->value; + value_b = &(*b)->value; + + if (value_a->type == GVT_UNSIGNED_INTEGER && value_b->type == GVT_UNSIGNED_INTEGER) + result = sort_unsigned_long_long(value_a->unsigned_integer, value_b->unsigned_integer); + + else if (value_a->type == GVT_UNSIGNED_INTEGER && value_b->type == GVT_UNSIGNED_INTEGER) + result = sort_signed_long_long(value_a->signed_integer, value_b->signed_integer); + + else + { + /** + * Le code Python a deux options : soit fournir un équivalent à la + * structure resolved_value_t lors de l'appel correspondant à cette + * fonction compare_enum_values_by_value(), soit fournir un nombre + * directement. + * + * Comme PyArg_ParseTuple() est obligée de trancher entre non-signé + * et signé, le parti est pris de considérer le non-signé coté Python. + * On s'adapte en conséquence ici. + * + * La structure resolved_value_t est une union, donc les valeurs + * sont potientiellement au mauvais format mais bien présentes. + */ + + /** + * result = sort_unsigned_long_long(value_a->type, value_b->type); + */ + + result = sort_unsigned_long_long(value_a->unsigned_integer, value_b->unsigned_integer); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = premières informations à consulter. * +* b = secondes informations à consulter. * +* * +* Description : Etablit la comparaison entre deux noms d'énumération. * +* * +* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int compare_enum_values_by_label(const enum_value_t **a, const enum_value_t **b) +{ + int result; /* Bilan à retourner */ + + result = strcmp((*a)->label, (*b)->label); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : l = premières informations à consulter. * +* b = secondes informations à consulter. * +* * +* Description : Etablit la comparaison entre deux noms d'énumération. * +* * +* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int compare_enum_values_by_sized_label(const sized_string_t *l, const enum_value_t **b) +{ + int result; /* Bilan à retourner */ + + result = strncmp(l->data, (*b)->label, l->len); // FIXME + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* GESTION D'UN GROUPE D'ENUMERATIONS */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un ensemble d'énumérations Kaitai. */ +G_DEFINE_TYPE(GKaitaiEnum, g_kaitai_enum, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des groupes d'énumérations Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_enum_class_init(GKaitaiEnumClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_enum_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_enum_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = instance à initialiser. * +* * +* Description : Initialise un groupe d'énumérations Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_enum_init(GKaitaiEnum *kenum) +{ + kenum->name = NULL; + + kenum->cases_v2l = NULL; + kenum->cases_v2l_count = 0; + + kenum->cases_l2v = NULL; + kenum->cases_l2v_count = 0; + + kenum->defcase = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_enum_dispose(GKaitaiEnum *kenum) +{ + G_OBJECT_CLASS(g_kaitai_enum_parent_class)->dispose(G_OBJECT(kenum)); + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_enum_finalize(GKaitaiEnum *kenum) +{ + size_t i; /* Boucle de parcours */ + + if (kenum->name != NULL) + free(kenum->name); + + for (i = 0; i < kenum->cases_v2l_count; i++) + delete_enum_value(kenum->cases_v2l[i]); + + if (kenum->cases_v2l != NULL) + free(kenum->cases_v2l); + + if (kenum->cases_l2v != NULL) + free(kenum->cases_l2v); + + if (kenum->defcase != NULL) + delete_enum_value(kenum->defcase); + + G_OBJECT_CLASS(g_kaitai_enum_parent_class)->finalize(G_OBJECT(kenum)); + +} + + +/****************************************************************************** +* * +* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. * +* * +* Description : Construit un groupe d'énumérations Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiEnum *g_kaitai_enum_new(GYamlNode *parent) +{ + GKaitaiEnum *result; /* Identifiant à retourner */ + + result = g_object_new(G_TYPE_KAITAI_ENUM, NULL); + + if (!g_kaitai_enum_create(result, parent)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = groupe d'énumérations à initialiser pleinement. * +* parent = noeud Yaml contenant l'attribut à constituer. * +* * +* Description : Met en place un groupe d'énumérations Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_enum_create(GKaitaiEnum *kenum, GYamlNode *parent) +{ + bool result; /* Bilan à retourner */ + char *path; /* Chemin des valeurs */ + GYamlNode *collec; /* Liste de noeuds à traiter */ + GYamlNode **nodes; /* Eventuels noeuds trouvés */ + size_t count; /* Quantité de ces noeuds */ + size_t i; /* Boucle de parcours */ + bool defcase; /* Définition par défaut ? */ + enum_value_t *value; /* Valeur énumérative nouvelle */ + bool found; /* Présence de partage existant*/ + size_t index; /* Indice du point d'insertion */ + + result = false; + + /* Récupération du nom */ + + if (!G_IS_YAML_PAIR(parent)) goto exit; + + kenum->name = strdup(g_yaml_pair_get_key(G_YAML_PAIR(parent))); + + /* Association de valeurs */ + + path = strdup("/"); + path = stradd(path, kenum->name); + path = stradd(path, "/"); + + collec = g_yaml_node_find_first_by_path(parent, path); + + free(path); + + if (collec != NULL) + { + if (G_IS_YAML_COLLEC(collec)) + nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count); + else + count = 0; + + if (count > 0) + { + for (i = 0; i < count; i++) + { + value = build_enum_value(nodes[i], &defcase); + if (value == NULL) break; + + if (defcase) + { + if (kenum->defcase != NULL) + { + log_variadic_message(LMT_WARNING, + _("Multiple definition of the defaut value for the enumeration '%s'"), + kenum->name); + + delete_enum_value(value); + break; + + } + + /** + * Exemple de choix par défaut : + * http://doc.kaitai.io/user_guide.html#tlv + */ + + kenum->defcase = value; + + } + + else + { + kenum->cases_v2l = qinsert(kenum->cases_v2l, &kenum->cases_v2l_count, sizeof(enum_value_t *), + (__compar_fn_t)compare_enum_values_by_value, &value); + + found = bsearch_index(&value, kenum->cases_l2v, kenum->cases_l2v_count, sizeof(enum_value_t *), + (__compar_fn_t)compare_enum_values_by_label, &index); + + if (found) + log_variadic_message(LMT_WARNING, + _("Multiple occurrence of the label %s in the enumeration '%s'"), + value->label, kenum->name); + + else + kenum->cases_l2v = _qinsert(kenum->cases_l2v, &kenum->cases_l2v_count, sizeof(enum_value_t *), + &value, index); + + } + + g_object_unref(G_OBJECT(nodes[i])); + + } + + result = (i == count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(nodes[i])); + + free(nodes); + + } + + g_object_unref(G_OBJECT(collec)); + + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = groupe d'énumérations à consulter. * +* * +* Description : Fournit le nom principal d'une énumération. * +* * +* Retour : Désignation de l'énumération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_kaitai_enum_get_name(const GKaitaiEnum *kenum) +{ + const char *result; /* Chaîne à retourner */ + + result = kenum->name; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = groupe d'énumérations à consulter. * +* label = étiquette de l'élément constant à traduire. * +* value = valeur concrète correspondante. [OUT] * +* * +* Description : Traduit une étiquette brute en constante d'énumération. * +* * +* Retour : Bilan de la conversion. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_enum_find_value(const GKaitaiEnum *kenum, const sized_string_t *label, resolved_value_t *value) +{ + bool result; /* Présence à retourner */ + size_t index; /* Indice du point d'insertion */ + + result = bsearch_index(label, kenum->cases_l2v, kenum->cases_l2v_count, sizeof(enum_value_t *), + (__compar_fn_t)compare_enum_values_by_sized_label, &index); + + if (result) + *value = kenum->cases_l2v[index]->value; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = groupe d'énumérations à consulter. * +* value = valeur concrète à transformer. * +* prefix = détermine l'ajout d'un préfixe éventuel. * +* * +* Description : Traduit une constante d'énumération en étiquette brute. * +* * +* Retour : Désignation ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_kaitai_enum_find_label(const GKaitaiEnum *kenum, const resolved_value_t *value, bool prefix) +{ + char *result; /* Etiquette à retourner */ + enum_value_t faked; /* Copie d'élément recherché */ + bool found; /* Présence de partage existant*/ + size_t index; /* Indice du point d'insertion */ + const enum_value_t *item; /* Elément retrouvé par valeur */ + + faked.value = *value; + + found = bsearch_index(&faked, kenum->cases_v2l, kenum->cases_v2l_count, sizeof(enum_value_t *), + (__compar_fn_t)compare_enum_values_by_value, &index); + + if (found) + item = kenum->cases_l2v[index]; + else + item = kenum->defcase; + + if (item != NULL) + { + if (prefix) + asprintf(&result, "%s::%s", kenum->name, item->label); + else + result = strdup(item->label); + } + + else + result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kenum = groupe d'énumérations à consulter. * +* value = valeur concrète à transformer. * +* * +* Description : Traduit une constante d'énumération en documentation. * +* * +* Retour : Documentation associée à la valeur indiquée ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +char *g_kaitai_enum_find_documentation(const GKaitaiEnum *kenum, const resolved_value_t *value) +{ + char *result; /* Documentation à retourner */ + enum_value_t faked; /* Copie d'élément recherché */ + bool found; /* Présence de partage existant*/ + size_t index; /* Indice du point d'insertion */ + const enum_value_t *item; /* Elément retrouvé par valeur */ + + faked.value = *value; + + found = bsearch_index(&faked, kenum->cases_v2l, kenum->cases_v2l_count, sizeof(enum_value_t *), + (__compar_fn_t)compare_enum_values_by_value, &index); + + if (found) + item = kenum->cases_l2v[index]; + else + item = kenum->defcase; + + if (item != NULL) + result = strdup(item->doc); + else + result = NULL; + + return result; + +} diff --git a/plugins/kaitai/parsers/enum.h b/plugins/kaitai/parsers/enum.h new file mode 100644 index 0000000..9e4bf2a --- /dev/null +++ b/plugins/kaitai/parsers/enum.h @@ -0,0 +1,76 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enum.h - prototypes pour la gestion des énumérations Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_ENUM_H +#define _PLUGINS_KAITAI_PARSERS_ENUM_H + + +#include <glib-object.h> +#include <stdbool.h> +#include <stdint.h> + + +#include <common/szstr.h> +#include <plugins/yaml/node.h> + + +#include "../expression.h" + + + +#define G_TYPE_KAITAI_ENUM g_kaitai_enum_get_type() +#define G_KAITAI_ENUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ENUM, GKaitaiEnum)) +#define G_IS_KAITAI_ENUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ENUM)) +#define G_KAITAI_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ENUM, GKaitaiEnumClass)) +#define G_IS_KAITAI_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ENUM)) +#define G_KAITAI_ENUM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ENUM, GKaitaiEnumClass)) + + +/* Définition d'un ensemble d'énumérations Kaitai (instance) */ +typedef struct _GKaitaiEnum GKaitaiEnum; + +/* Définition d'un ensemble d'énumérations Kaitai (classe) */ +typedef struct _GKaitaiEnumClass GKaitaiEnumClass; + + +/* Indique le type défini pour un ensemble d'énumérations Kaitai. */ +GType g_kaitai_enum_get_type(void); + +/* Construit un groupe d'énumérations Kaitai. */ +GKaitaiEnum *g_kaitai_enum_new(GYamlNode *); + +/* Fournit le nom principal d'une énumération. */ +const char *g_kaitai_enum_get_name(const GKaitaiEnum *); + +/* Traduit une étiquette brute en constante d'énumération. */ +bool g_kaitai_enum_find_value(const GKaitaiEnum *, const sized_string_t *, resolved_value_t *); + +/* Traduit une constante d'énumération en étiquette brute. */ +char *g_kaitai_enum_find_label(const GKaitaiEnum *, const resolved_value_t *, bool); + +/* Traduit une constante d'énumération en documentation. */ +char *g_kaitai_enum_find_documentation(const GKaitaiEnum *, const resolved_value_t *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_ENUM_H */ diff --git a/plugins/kaitai/parsers/instance-int.h b/plugins/kaitai/parsers/instance-int.h new file mode 100644 index 0000000..6f098b4 --- /dev/null +++ b/plugins/kaitai/parsers/instance-int.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instance-int.h - prototypes pour les spécifications internes d'une instance Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H +#define _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H + + +#include "attribute-int.h" +#include "instance.h" + + + +/* Spécification d'une instance Kaitai (instance) */ +struct _GKaitaiInstance +{ + GKaitaiAttribute parent; /* A laisser en premier */ + + char *name; /* Nom attribué à l'instance */ + + char *io; /* Contenu binaire forcé */ + char *pos; /* Position forcée */ + char *value; /* Formule pour calcul */ + +}; + +/* Spécification d'une instance Kaitai (classe) */ +struct _GKaitaiInstanceClass +{ + GKaitaiAttributeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un lecteur d'instance Kaitai. */ +bool g_kaitai_instance_create(GKaitaiInstance *, GYamlNode *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H */ diff --git a/plugins/kaitai/parsers/instance.c b/plugins/kaitai/parsers/instance.c new file mode 100644 index 0000000..d62c1f6 --- /dev/null +++ b/plugins/kaitai/parsers/instance.c @@ -0,0 +1,503 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instance.c - spécification d'une instance Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "instance.h" + + +#include <assert.h> +#include <malloc.h> +#include <string.h> + + +#include <plugins/yaml/pair.h> + + +#include "instance-int.h" +#include "../expression.h" +#include "../records/delayed.h" + + + +/* -------------------- CORRESPONDANCE ENTRE INSTANCE ET BINAIRE -------------------- */ + + +/* Initialise la classe des instances de spécification Kaitai. */ +static void g_kaitai_instance_class_init(GKaitaiInstanceClass *); + +/* Initialise une instance de spécification Kaitai. */ +static void g_kaitai_instance_init(GKaitaiInstance *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_instance_dispose(GKaitaiInstance *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_instance_finalize(GKaitaiInstance *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Parcourt un contenu binaire selon des spécifications Kaitai. */ +static bool g_kaitai_instance_parse_content(GKaitaiInstance *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **); + + + +/* ---------------------------------------------------------------------------------- */ +/* CORRESPONDANCE ENTRE INSTANCE ET BINAIRE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une instance de la spécification Kaitai. */ +G_DEFINE_TYPE(GKaitaiInstance, g_kaitai_instance, G_TYPE_KAITAI_ATTRIBUTE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des instances de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_instance_class_init(GKaitaiInstanceClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GKaitaiParserClass *parser; /* Ancêtre parent de la classe */ + GKaitaiAttributeClass *attrib; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_instance_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_instance_finalize; + + parser = G_KAITAI_PARSER_CLASS(klass); + + parser->parse = (parse_kaitai_fc)g_kaitai_instance_parse_content; + + attrib = G_KAITAI_ATTRIBUTE_CLASS(klass); + + attrib->get_label = (get_attribute_label_fc)g_kaitai_instance_get_name; + +} + + +/****************************************************************************** +* * +* Paramètres : inst = instance à initialiser. * +* * +* Description : Initialise une instance de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_instance_init(GKaitaiInstance *inst) +{ + inst->name = NULL; + + inst->io = NULL; + inst->pos = NULL; + inst->value = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : inst = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_instance_dispose(GKaitaiInstance *inst) +{ + G_OBJECT_CLASS(g_kaitai_instance_parent_class)->dispose(G_OBJECT(inst)); + +} + + +/****************************************************************************** +* * +* Paramètres : inst = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_instance_finalize(GKaitaiInstance *inst) +{ + if (inst->name != NULL) + free(inst->name); + + if (inst->io != NULL) + free(inst->io); + + if (inst->pos != NULL) + free(inst->pos); + + if (inst->value != NULL) + free(inst->value); + + G_OBJECT_CLASS(g_kaitai_instance_parent_class)->finalize(G_OBJECT(inst)); + +} + + +/****************************************************************************** +* * +* Paramètres : parent = noeud Yaml contenant l'instance à constituer. * +* * +* Description : Construit un lecteur d'instance Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiInstance *g_kaitai_instance_new(GYamlNode *parent) +{ + GKaitaiInstance *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_INSTANCE, NULL); + + if (!g_kaitai_instance_create(result, parent)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : inst = lecteur d'instance Kaitai à initialiser pleinement. * +* parent = noeud Yaml contenant l'instance à constituer. * +* * +* Description : Met en place un lecteur d'instance Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_instance_create(GKaitaiInstance *inst, GYamlNode *parent) +{ + bool result; /* Bilan à retourner */ + const char *name; /* Désignation du type */ + char *sub_path; /* Chemin d'accès suivant */ + GYamlNode *sub; /* Contenu Yaml d'un type */ + GYamlNode *node; /* Noeud particulier présent */ + const char *value; /* Valeur Yaml particulière */ + + result = false; + + /* Extraction du nom */ + + if (!G_IS_YAML_PAIR(parent)) + goto exit; + + name = g_yaml_pair_get_key(G_YAML_PAIR(parent)); + + inst->name = strdup(name); + + /* Extraction des bases du type */ + + asprintf(&sub_path, "/%s/", name); + sub = g_yaml_node_find_first_by_path(parent, sub_path); + free(sub_path); + + if (sub == NULL) + goto exit; + + result = g_kaitai_attribute_create(G_KAITAI_ATTRIBUTE(inst), sub, false); + + /* Eventuel contenu imposé */ + + node = g_yaml_node_find_first_by_path(sub, "/io"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + if (value == NULL) + { + g_object_unref(G_OBJECT(node)); + goto bad_loading; + } + + inst->io = strdup(value); + + g_object_unref(G_OBJECT(node)); + + } + + /* Eventuelle positiion imposée */ + + node = g_yaml_node_find_first_by_path(sub, "/pos"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + if (value == NULL) + { + g_object_unref(G_OBJECT(node)); + goto bad_loading; + } + + inst->pos = strdup(value); + + g_object_unref(G_OBJECT(node)); + + } + + /* Eventuelle formule de calcul d'une valeur */ + + node = g_yaml_node_find_first_by_path(sub, "/value"); + + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); + + inst->value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node)); + + g_object_unref(G_OBJECT(node)); + + if (inst->value == NULL) + goto bad_loading; + + } + + bad_loading: + + g_object_unref(G_OBJECT(sub)); + + exit: + + if (result) + result = (inst->pos != NULL || inst->value != NULL); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : inst = lecteur d'instance Kaitai à consulter. * +* * +* Description : Indique le nom attribué à une instance Kaitai. * +* * +* Retour : Désignation pointant l'instance. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_kaitai_instance_get_name(const GKaitaiInstance *inst) +{ + char *result; /* Valeur à renvoyer */ + + result = inst->name; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : inst = lecteur d'instance Kaitai à consulter. * +* locals = variables locales pour les résolutions de types. * +* content = contenu binaire lié à la correspondance. * +* * +* Description : Détermine la valeur effective d'un élément Kaitai dynamique. * +* * +* Retour : valeur à sauvegarder sous une forme générique. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *g_kaitai_instance_compute_real_record(const GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content) +{ + GMatchRecord *result; /* Enregistrement à retourner */ + GBinContent *work_area; /* Aire de travail */ + GKaitaiStream *stream; /* Flux de données pour Kaitai */ + bool status; /* Bilan intermédiaire */ + vmpa2t forced_pos; /* Tete de lecture constituée */ + resolved_value_t offset; /* Position à adopter */ + GKaitaiParserClass *class; /* Classe parente à solliciter */ + ext_vmpa_t epos; /* Tête de lecture complète */ + + result = NULL; + + if (inst->value == NULL) + { + /* Contenu particulier */ + + if (inst->io == NULL) + work_area = content; + + else + { + status = resolve_kaitai_expression_as_stream(locals, inst->io, strlen(inst->io), &stream); + if (!status) goto exit; + + work_area = g_kaitai_stream_get_content(stream); + + g_object_unref(G_OBJECT(stream)); + + } + + /* Tête de lecture */ + + g_binary_content_compute_start_pos(work_area, &forced_pos); + + status = resolve_kaitai_expression_as_integer(locals, inst->pos, strlen(inst->pos), &offset); + if (!status) goto exit_with_content; + + if (offset.type == GVT_UNSIGNED_INTEGER) + advance_vmpa(&forced_pos, offset.unsigned_integer); + + else + { + assert(offset.type == GVT_SIGNED_INTEGER); + + if (offset.signed_integer < 0) + { + status = false; + goto exit_with_content; + } + + advance_vmpa(&forced_pos, offset.signed_integer); + + } + + /* Lecture */ + + class = G_KAITAI_PARSER_CLASS(g_kaitai_instance_parent_class); + + init_evmpa_from_vmpa(&epos, &forced_pos); + + class->parse(G_KAITAI_PARSER(inst), locals, work_area, &epos, &result); + + exit_with_content: + + if (work_area != content) + g_object_unref(G_OBJECT(work_area)); + + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : inst = lecteur d'instance Kaitai à consulter. * +* locals = variables locales pour les résolutions de types. * +* value = valeur à sauvegarder sous une forme générique. [OUT]* +* * +* Description : Détermine la valeur d'un élément Kaitai entier calculé. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_instance_compute_value(const GKaitaiInstance *inst, const kaitai_scope_t *locals, resolved_value_t *value) +{ + bool result; /* Bilan à retourner */ + + if (inst->value == NULL) + result = false; + + else + result = resolve_kaitai_expression_as_any(locals, + inst->value, + strlen(inst->value), + value); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : inst = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* epos = tête de lecture courante. [OUT] * +* record = noeud d'arborescence d'éléments rencontrés. [OUT] * +* * +* Description : Parcourt un contenu binaire selon des spécifications Kaitai. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record) +{ + bool result; /* Bilan à retourner */ + + *record = G_MATCH_RECORD(g_record_delayed_new(inst, locals, inst->value == NULL ? content : NULL)); + + result = (*record != NULL); + + return result; + +} diff --git a/plugins/kaitai/parsers/instance.h b/plugins/kaitai/parsers/instance.h new file mode 100644 index 0000000..4594137 --- /dev/null +++ b/plugins/kaitai/parsers/instance.h @@ -0,0 +1,71 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instance.h - prototypes pour la spécification d'une instance Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_INSTANCE_H +#define _PLUGINS_KAITAI_PARSERS_INSTANCE_H + + +#include <glib-object.h> + + +#include <plugins/yaml/node.h> + + +#include "../expression.h" +#include "../scope.h" + + + +#define G_TYPE_KAITAI_INSTANCE g_kaitai_instance_get_type() +#define G_KAITAI_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_INSTANCE, GKaitaiInstance)) +#define G_IS_KAITAI_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_INSTANCE)) +#define G_KAITAI_INSTANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_INSTANCE, GKaitaiInstanceClass)) +#define G_IS_KAITAI_INSTANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_INSTANCE)) +#define G_KAITAI_INSTANCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_INSTANCE, GKaitaiInstanceClass)) + + +/* Spécification d'une instance Kaitai (instance) */ +typedef struct _GKaitaiInstance GKaitaiInstance; + +/* Spécification d'une instance Kaitai (classe) */ +typedef struct _GKaitaiInstanceClass GKaitaiInstanceClass; + + +/* Indique le type défini pour une instance de la spécification Kaitai. */ +GType g_kaitai_instance_get_type(void); + +/* Construit un lecteur d'instance Kaitai. */ +GKaitaiInstance *g_kaitai_instance_new(GYamlNode *); + +/* Indique le nom attribué à une instance Kaitai. */ +const char *g_kaitai_instance_get_name(const GKaitaiInstance *); + +/* Détermine la valeur effective d'un élément Kaitai dynamique. */ +GMatchRecord *g_kaitai_instance_compute_real_record(const GKaitaiInstance *, const kaitai_scope_t *, GBinContent *); + +/* Détermine la valeur d'un élément Kaitai entier calculé. */ +bool g_kaitai_instance_compute_value(const GKaitaiInstance *, const kaitai_scope_t *, resolved_value_t *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_INSTANCE_H */ diff --git a/plugins/kaitai/parsers/meta-int.h b/plugins/kaitai/parsers/meta-int.h new file mode 100644 index 0000000..5fe9174 --- /dev/null +++ b/plugins/kaitai/parsers/meta-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * meta-int.h - prototypes internes pour la description globale d'une définition Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_PARSERS_META_INT_H +#define PLUGINS_KAITAI_PARSERS_META_INT_H + + +#include "meta.h" + + + +/* Description globale d'une définition Kaitai (instance) */ +struct _GKaitaiMeta +{ + GObject parent; /* A laisser en premier */ + + char *id; /* Identifiant attribué */ + char *title; /* Désignation de la définition*/ + + SourceEndian endian; /* Boutisme par défaut */ + + char **dependencies; /* Définitions à importer */ + size_t dep_count; /* Nombre de ces définitions */ + +}; + +/* Description globale d'une définition Kaitai (classe) */ +struct _GKaitaiMetaClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une description globale Kaitai. */ +bool g_kaitai_meta_create(GKaitaiMeta *, GYamlNode *); + + + +#endif /* PLUGINS_KAITAI_PARSERS_META_INT_H */ diff --git a/plugins/yaml/line.c b/plugins/kaitai/parsers/meta.c index 26a1012..132eefd 100644 --- a/plugins/yaml/line.c +++ b/plugins/kaitai/parsers/meta.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * line.c - ligne de contenu Yaml + * meta.c - description globale d'une définition Kaitai * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,66 +21,44 @@ */ -#include "line.h" +#include "meta.h" +#include <assert.h> #include <malloc.h> #include <string.h> -#include <core/logs.h> +#include <plugins/yaml/pair.h> +#include "meta-int.h" -/* Ligne de données au format Yaml (instance) */ -struct _GYamlLine -{ - GObject parent; /* A laisser en premier */ - - char *raw; /* Contenu brut de la ligne */ - size_t number; /* Indice associé */ - - size_t indent; /* Niveau d'indentation */ - bool is_list_item; /* Elément de liste ? */ - - const char *payload; /* Charge utile du contenu */ - - char *key; /* Clef de la ligne Yaml */ - char *value; /* Valeyr de la ligne Yaml */ - -}; - -/* Ligne de données au format Yaml (classe) */ -struct _GYamlLineClass -{ - GObjectClass parent; /* A laisser en premier */ -}; +/* Initialise la classe des descriptions globales Kaitai. */ +static void g_kaitai_meta_class_init(GKaitaiMetaClass *); -/* Initialise la classe des lignes de contenu Yaml. */ -static void g_yaml_line_class_init(GYamlLineClass *); - -/* Initialise une instance de ligne de contenu Yaml. */ -static void g_yaml_line_init(GYamlLine *); +/* Initialise une description globale de définition Kaitai. */ +static void g_kaitai_meta_init(GKaitaiMeta *); /* Supprime toutes les références externes. */ -static void g_yaml_line_dispose(GYamlLine *); +static void g_kaitai_meta_dispose(GKaitaiMeta *); /* Procède à la libération totale de la mémoire. */ -static void g_yaml_line_finalize(GYamlLine *); +static void g_kaitai_meta_finalize(GKaitaiMeta *); -/* Indique le type défini pour une ligne de données au format Yaml. */ -G_DEFINE_TYPE(GYamlLine, g_yaml_line, G_TYPE_OBJECT); +/* Indique le type défini pour une description globale Kaitai. */ +G_DEFINE_TYPE(GKaitaiMeta, g_kaitai_meta, G_TYPE_OBJECT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des lignes de contenu Yaml. * +* Description : Initialise la classe des descriptions globales Kaitai. * * * * Retour : - * * * @@ -88,23 +66,23 @@ G_DEFINE_TYPE(GYamlLine, g_yaml_line, G_TYPE_OBJECT); * * ******************************************************************************/ -static void g_yaml_line_class_init(GYamlLineClass *klass) +static void g_kaitai_meta_class_init(GKaitaiMetaClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_line_dispose; - object->finalize = (GObjectFinalizeFunc)g_yaml_line_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_meta_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_meta_finalize; } /****************************************************************************** * * -* Paramètres : line = instance à initialiser. * +* Paramètres : meta = instance à initialiser. * * * -* Description : Initialise une instance de ligne de contenu Yaml. * +* Description : Initialise une description globale de définition Kaitai. * * * * Retour : - * * * @@ -112,24 +90,22 @@ static void g_yaml_line_class_init(GYamlLineClass *klass) * * ******************************************************************************/ -static void g_yaml_line_init(GYamlLine *line) +static void g_kaitai_meta_init(GKaitaiMeta *meta) { - line->raw = NULL; - line->number = -1; + meta->id = NULL; + meta->title = NULL; - line->indent = 0; - line->is_list_item = false; + meta->endian = SRE_LITTLE; - line->payload = NULL; - line->key = NULL; - line->value = NULL; + meta->dependencies = NULL; + meta->dep_count = 0; } /****************************************************************************** * * -* Paramètres : line = instance d'objet GLib à traiter. * +* Paramètres : meta = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -139,16 +115,16 @@ static void g_yaml_line_init(GYamlLine *line) * * ******************************************************************************/ -static void g_yaml_line_dispose(GYamlLine *line) +static void g_kaitai_meta_dispose(GKaitaiMeta *meta) { - G_OBJECT_CLASS(g_yaml_line_parent_class)->dispose(G_OBJECT(line)); + G_OBJECT_CLASS(g_kaitai_meta_parent_class)->dispose(G_OBJECT(meta)); } /****************************************************************************** * * -* Paramètres : line = instance d'objet GLib à traiter. * +* Paramètres : meta = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -158,28 +134,32 @@ static void g_yaml_line_dispose(GYamlLine *line) * * ******************************************************************************/ -static void g_yaml_line_finalize(GYamlLine *line) +static void g_kaitai_meta_finalize(GKaitaiMeta *meta) { - if (line->raw != NULL) - free(line->raw); + size_t i; /* Boucle de parcours */ + + if (meta->id != NULL) + free(meta->id); - if (line->key != NULL) - free(line->key); + if (meta->title != NULL) + free(meta->title); - if (line->value != NULL) - free(line->value); + for (i = 0; i < meta->dep_count; i++) + free(meta->dependencies[i]); - G_OBJECT_CLASS(g_yaml_line_parent_class)->finalize(G_OBJECT(line)); + if (meta->dependencies != NULL) + free(meta->dependencies); + + G_OBJECT_CLASS(g_kaitai_meta_parent_class)->finalize(G_OBJECT(meta)); } /****************************************************************************** * * -* Paramètres : raw = contenu brut d'une ligne au format Yaml. * -* number = indice associé à la ligne. * +* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. * * * -* Description : Met en place un gestionnaire pour ligne au format Yaml. * +* Description : Construit une description globale Kaitai. * * * * Retour : Instance mise en place ou NULL en cas d'échec. * * * @@ -187,120 +167,136 @@ static void g_yaml_line_finalize(GYamlLine *line) * * ******************************************************************************/ -GYamlLine *g_yaml_line_new(const char *raw, size_t number) +GKaitaiMeta *g_kaitai_meta_new(GYamlNode *parent) { - GYamlLine *result; /* Structure à retourner */ - char *iter; /* Boucle de parcours */ - bool string_content[2]; /* Ouvertures de chaînes */ - bool escape; /* Echappement de marquant */ + GKaitaiMeta *result; /* Identifiant à retourner */ - result = g_object_new(G_TYPE_YAML_LINE, NULL); + result = g_object_new(G_TYPE_KAITAI_META, NULL); - result->raw = strdup(raw); - result->number = number; + if (!g_kaitai_meta_create(result, parent)) + g_clear_object(&result); - /* Indentation */ + return result; - for (iter = result->raw; *iter != '\0'; iter++) - { - if (*iter != ' ') - break; +} - result->indent++; - } +/****************************************************************************** +* * +* Paramètres : meta = description globale à initialiser pleinement. * +* parent = noeud Yaml contenant l'attribut à constituer. * +* * +* Description : Met en place une description globale Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - if (*iter == '-') +bool g_kaitai_meta_create(GKaitaiMeta *meta, GYamlNode *parent) +{ + bool result; /* Bilan à retourner */ + GYamlNode *node; /* Noeud particulier présent */ + const char *value; /* Valeur Yaml particulière */ + GYamlNode **nodes; /* Eventuels noeuds trouvés */ + size_t count; /* Quantité de ces noeuds */ + size_t i; /* Boucle de parcours */ + + result = true; + + /* Identifiant */ + + node = g_yaml_node_find_first_by_path(parent, "/meta/id"); + + if (node != NULL) { - result->is_list_item = true; + assert(G_IS_YAML_PAIR(node)); - for (iter++; *iter != '\0'; iter++) - if (*iter != ' ') - break; + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); - } + if (value != NULL) + meta->id = strdup(value); + + g_object_unref(G_OBJECT(node)); - result->payload = iter; + } - /* Eventuel couple clef/valeur */ + /* Titre */ - string_content[0] = false; - string_content[1] = false; + node = g_yaml_node_find_first_by_path(parent, "/meta/title"); - for (; *iter != '\0'; iter++) + if (node != NULL) { - if (*iter == '\'' && !string_content[1]) - { - if (iter == result->payload) - escape = false; + assert(G_IS_YAML_PAIR(node)); - else - escape = *(iter - 1) == '\''; + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); - if (!escape) - string_content[0] = !string_content[0]; + if (value != NULL) + meta->title = strdup(value); - } + g_object_unref(G_OBJECT(node)); - else if (*iter == '"' && !string_content[0]) - { - if (iter == result->payload) - escape = false; + } - else - escape = *(iter - 1) == '\\'; + /* Boutisme */ - if (!escape) - string_content[1] = !string_content[1]; + node = g_yaml_node_find_first_by_path(parent, "/meta/endian"); - } + if (node != NULL) + { + assert(G_IS_YAML_PAIR(node)); - else if (!string_content[0] && !string_content[1]) - { + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); - if (*iter == ':') - break; + if (strcmp(value, "le") == 0) + meta->endian = SRE_LITTLE; + else if (strcmp(value, "be") == 0) + meta->endian = SRE_BIG; - } + g_object_unref(G_OBJECT(node)); } - if (*iter != '\0') + /* Imports */ + + node = g_yaml_node_find_first_by_path(parent, "/meta/imports/"); + + if (node != NULL) { - result->key = strndup(result->payload, iter - result->payload); + result = G_IS_YAML_COLLEC(node); - for (iter++; *iter != '\0'; iter++) - if (*iter != ' ') - break; + if (result) + { + nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(node), &count); - if (*iter != '\0') - result->value = strdup(iter); + for (i = 0; i < count; i++) + { + if (!G_IS_YAML_PAIR(nodes[i])) + break; - } + value = g_yaml_pair_get_key(G_YAML_PAIR(nodes[i])); - return result; + meta->dependencies = realloc(meta->dependencies, ++meta->dep_count * sizeof(char *)); -} + meta->dependencies[meta->dep_count - 1] = strdup(value); + g_object_unref(G_OBJECT(nodes[i])); -/****************************************************************************** -* * -* Paramètres : line = ligne au format Yaml à consulter. * -* * -* Description : Fournit la taille de l'indentation d'une ligne Yaml. * -* * -* Retour : Taille de l'indentation rencontrée. * -* * -* Remarques : - * -* * -******************************************************************************/ + } -size_t g_yaml_line_count_indent(const GYamlLine *line) -{ - size_t result; /* Quantité à retourner */ + result = (i == count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(nodes[i])); - result = line->indent; + if (nodes != NULL) + free(nodes); + + } + + } return result; @@ -309,21 +305,21 @@ size_t g_yaml_line_count_indent(const GYamlLine *line) /****************************************************************************** * * -* Paramètres : line = ligne au format Yaml à consulter. * +* Paramètres : meta = description globale à consulter. * * * -* Description : Indique si la ligne représente un élément de liste. * +* Description : Fournit l'identifié associé à une définiton Kaitai. * * * -* Retour : Statut de l'état lié à une liste d'éléments. * +* Retour : Identifiant de définition complète ou NULL. * * * * Remarques : - * * * ******************************************************************************/ -bool g_yaml_line_is_list_item(const GYamlLine *line) +const char *g_kaitai_meta_get_id(const GKaitaiMeta *meta) { - bool result; /* Statut à retourner */ + const char *result; /* Chaîne à retourner */ - result = line->is_list_item; + result = meta->id; return result; @@ -332,21 +328,21 @@ bool g_yaml_line_is_list_item(const GYamlLine *line) /****************************************************************************** * * -* Paramètres : line = ligne au format Yaml à consulter. * +* Paramètres : meta = description globale à consulter. * * * -* Description : Fournit la charge utile associée à une ligne Yaml. * +* Description : Fournit la désignation humaine d'une définiton Kaitai. * * * -* Retour : Contenu sous forme de chaîne de caractères. * +* Retour : Intitulé de définition ou NULL. * * * * Remarques : - * * * ******************************************************************************/ -const char *g_yaml_line_get_payload(const GYamlLine *line) +const char *g_kaitai_meta_get_title(const GKaitaiMeta *meta) { - const char *result; /* Valeur à retourner */ + const char *result; /* Chaîne à retourner */ - result = line->payload; + result = meta->title; return result; @@ -355,21 +351,21 @@ const char *g_yaml_line_get_payload(const GYamlLine *line) /****************************************************************************** * * -* Paramètres : line = ligne au format Yaml à consulter. * +* Paramètres : meta = description globale à consulter. * * * -* Description : Fournit la clef associée à une ligne Yaml si elle existe. * +* Description : Indique le boustime observé par défaut par une définiton. * * * -* Retour : Clef sous forme de chaîne de caractères ou NULL. * +* Retour : Boustime, petit par défaut. * * * * Remarques : - * * * ******************************************************************************/ -const char *g_yaml_line_get_key(const GYamlLine *line) +SourceEndian g_kaitai_meta_get_endian(const GKaitaiMeta *meta) { - char *result; /* Valeur à retourner */ + SourceEndian result; /* Chaîne à retourner */ - result = line->key; + result = meta->endian; return result; @@ -378,21 +374,24 @@ const char *g_yaml_line_get_key(const GYamlLine *line) /****************************************************************************** * * -* Paramètres : line = ligne au format Yaml à consulter. * +* Paramètres : meta = description globale à consulter. * +* count = quantité de définitions à importer. [OUT] * * * -* Description : Fournit la valeur associée à une ligne Yaml si elle existe. * +* Description : Indique la liste des définitions à importer. * * * -* Retour : Valeur sous forme de chaîne de caractères ou NULL. * +* Retour : Liste de désignations de définitions ou NULL. * * * * Remarques : - * * * ******************************************************************************/ -const char *g_yaml_line_get_value(const GYamlLine *line) +const char * const *g_kaitai_meta_get_dependencies(const GKaitaiMeta *meta, size_t *count) { - char *result; /* Valeur à retourner */ + const char * const *result; /* Liste à retourner */ + + result = (const char * const *)meta->dependencies; - result = line->value; + *count = meta->dep_count; return result; diff --git a/plugins/kaitai/parsers/meta.h b/plugins/kaitai/parsers/meta.h new file mode 100644 index 0000000..b8b685d --- /dev/null +++ b/plugins/kaitai/parsers/meta.h @@ -0,0 +1,71 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * meta.h - prototypes pour la description globale d'une définition Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_META_H +#define _PLUGINS_KAITAI_PARSERS_META_H + + +#include <glib-object.h> + + +#include <common/endianness.h> +#include <plugins/yaml/node.h> + + + +#define G_TYPE_KAITAI_META g_kaitai_meta_get_type() +#define G_KAITAI_META(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_META, GKaitaiMeta)) +#define G_IS_KAITAI_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_META)) +#define G_KAITAI_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_META, GKaitaiMetaClass)) +#define G_IS_KAITAI_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_META)) +#define G_KAITAI_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_META, GKaitaiMetaClass)) + + +/* Description globale d'une définition Kaitai (instance) */ +typedef struct _GKaitaiMeta GKaitaiMeta; + +/* Description globale d'une définition Kaitai (classe) */ +typedef struct _GKaitaiMetaClass GKaitaiMetaClass; + + +/* Indique le type défini pour une description globale Kaitai. */ +GType g_kaitai_meta_get_type(void); + +/* Construit une description globale Kaitai. */ +GKaitaiMeta *g_kaitai_meta_new(GYamlNode *); + +/* Fournit l'identifié associé à une définiton Kaitai. */ +const char *g_kaitai_meta_get_id(const GKaitaiMeta *); + +/* Fournit la désignation humaine d'une définiton Kaitai. */ +const char *g_kaitai_meta_get_title(const GKaitaiMeta *); + +/* Indique le boustime observé par défaut par une définiton. */ +SourceEndian g_kaitai_meta_get_endian(const GKaitaiMeta *); + +/* Indique la liste des définitions à importer. */ +const char * const *g_kaitai_meta_get_dependencies(const GKaitaiMeta *, size_t *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_META_H */ diff --git a/plugins/kaitai/parsers/struct-int.h b/plugins/kaitai/parsers/struct-int.h new file mode 100644 index 0000000..6eb6e53 --- /dev/null +++ b/plugins/kaitai/parsers/struct-int.h @@ -0,0 +1,77 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * struct-int.h - prototypes internes pour la définition d'une structure Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_PARSERS_STRUCT_INT_H +#define PLUGINS_KAITAI_PARSERS_STRUCT_INT_H + + +#include "attribute.h" +#include "instance.h" +#include "struct.h" +#include "../parser-int.h" + + + +/* Spécification d'une structure Kaitai (instance) */ +struct _GKaitaiStruct +{ + GKaitaiParser parent; /* A laisser en premier */ + + char *filename; /* Eventuelle source de données*/ + + GKaitaiMeta *meta; /* Description globale */ + + GKaitaiAttribute **seq_items; /* Sous-attributs présents */ + size_t seq_items_count; /* Quantité de ces attributs */ + + GKaitaiType **types; /* Types particuliers définis */ + size_t types_count; /* Quantité de ces types */ + + GKaitaiInstance **instances; /* Instances prises en charge */ + size_t instances_count; /* Quantité de ces instances */ + + GKaitaiEnum **enums; /* Enumérations locales */ + size_t enums_count; /* Quantité de ces énumérations*/ + +}; + +/* Spécification d'une structure Kaitai (classe) */ +struct _GKaitaiStructClass +{ + GKaitaiParserClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un interpréteur de définitions Kaitai. */ +bool g_kaitai_structure_create_from_text(GKaitaiStruct *, const char *); + +/* Met en place un interpréteur de définitions Kaitai. */ +bool g_kaitai_structure_create_from_file(GKaitaiStruct *, const char *); + +/* Met en place un lecteur de définitions Kaitai. */ +bool g_kaitai_structure_create(GKaitaiStruct *, GYamlNode *); + + + +#endif /* PLUGINS_KAITAI_PARSERS_STRUCT_INT_H */ diff --git a/plugins/kaitai/parsers/struct.c b/plugins/kaitai/parsers/struct.c new file mode 100644 index 0000000..d447cf3 --- /dev/null +++ b/plugins/kaitai/parsers/struct.c @@ -0,0 +1,837 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * struct.c - définition d'une structure Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "struct.h" + + +#include <assert.h> +#include <string.h> + + +#include <plugins/yaml/collection.h> +#include <plugins/yaml/parser.h> + + +#include "struct-int.h" +#include "../import.h" +#include "../parser.h" +#include "../records/empty.h" +#include "../records/group.h" + + + +/* ---------------------- LECTURE D'UNE TRANCHE DE DEFINITIONS ---------------------- */ + + +/* Initialise la classe des structuts de spécification Kaitai. */ +static void g_kaitai_structure_class_init(GKaitaiStructClass *); + +/* Initialise un structut de spécification Kaitai. */ +static void g_kaitai_structure_init(GKaitaiStruct *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_structure_dispose(GKaitaiStruct *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_structure_finalize(GKaitaiStruct *); + +/* Charge les éventuelles dépendances de la définition. */ +static bool g_kaitai_structure_load_imports(GKaitaiStruct *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Parcourt un contenu binaire selon des spécifications Kaitai. */ +static bool g_kaitai_structure_parse_content(GKaitaiStruct *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **); + + + +/* ---------------------------------------------------------------------------------- */ +/* LECTURE D'UNE TRANCHE DE DEFINITIONS */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un structut de la spécification Kaitai. */ +G_DEFINE_TYPE(GKaitaiStruct, g_kaitai_structure, G_TYPE_KAITAI_PARSER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des structuts de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_structure_class_init(GKaitaiStructClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GKaitaiParserClass *parser; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_structure_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_structure_finalize; + + parser = G_KAITAI_PARSER_CLASS(klass); + + parser->parse = (parse_kaitai_fc)g_kaitai_structure_parse_content; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = instance à initialiser. * +* * +* Description : Initialise un structure de spécification Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_structure_init(GKaitaiStruct *kstruct) +{ + kstruct->filename = NULL; + + kstruct->meta = NULL; + + kstruct->seq_items = NULL; + kstruct->seq_items_count = 0; + + kstruct->types = NULL; + kstruct->types_count = 0; + + kstruct->instances = NULL; + kstruct->instances_count = 0; + + kstruct->enums = NULL; + kstruct->enums_count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_structure_dispose(GKaitaiStruct *kstruct) +{ + size_t i; /* Boucle de parcours */ + + g_clear_object(&kstruct->meta); + + for (i = 0; i < kstruct->seq_items_count; i++) + g_clear_object(&kstruct->seq_items[i]); + + for (i = 0; i < kstruct->types_count; i++) + g_clear_object(&kstruct->types[i]); + + for (i = 0; i < kstruct->instances_count; i++) + g_clear_object(&kstruct->instances[i]); + + for (i = 0; i < kstruct->enums_count; i++) + g_clear_object(&kstruct->enums[i]); + + G_OBJECT_CLASS(g_kaitai_structure_parent_class)->dispose(G_OBJECT(kstruct)); + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_structure_finalize(GKaitaiStruct *kstruct) +{ + if (kstruct->filename != NULL) + free(kstruct->filename); + + if (kstruct->seq_items != NULL) + free(kstruct->seq_items); + + if (kstruct->types != NULL) + free(kstruct->types); + + if (kstruct->instances != NULL) + free(kstruct->instances); + + if (kstruct->enums != NULL) + free(kstruct->enums); + + G_OBJECT_CLASS(g_kaitai_structure_parent_class)->finalize(G_OBJECT(kstruct)); + +} + + +/****************************************************************************** +* * +* Paramètres : text = définitions textuelles d'un contenu brut. * +* * +* Description : Crée un nouvel interpréteur de structure Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiStruct *g_kaitai_structure_new_from_text(const char *text) +{ + GKaitaiStruct *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_STRUCT, NULL); + + if (!g_kaitai_structure_create_from_text(result, text)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = lecteur de définition à initialiser pleinement. * +* text = définitions textuelles d'un contenu brut. * +* * +* Description : Met en place un interpréteur de définitions Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_structure_create_from_text(GKaitaiStruct *kstruct, const char *text) +{ + bool result; /* Bilan à retourner */ + GYamlNode *root; /* Noeud racine YAML */ + + root = parse_yaml_from_text(text, strlen(text)); + + if (root != NULL) + { + result = g_kaitai_structure_create(kstruct, root); + g_object_unref(G_OBJECT(root)); + } + else + { + fprintf(stderr, "The provided YAML content seems invalid"); + result = false; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : filename = chemin vers des définitions de règles. * +* * +* Description : Crée un nouvel interpréteur de structure Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiStruct *g_kaitai_structure_new_from_file(const char *filename) +{ + GKaitaiStruct *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_STRUCT, NULL); + + if (!g_kaitai_structure_create_from_file(result, filename)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = lecteur de définition à initialiser pleinement. * +* filename = chemin vers des définitions de règles. * +* * +* Description : Met en place un interpréteur de définitions Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_structure_create_from_file(GKaitaiStruct *kstruct, const char *filename) +{ + bool result; /* Bilan à retourner */ + GYamlNode *root; /* Noeud racine YAML */ + + kstruct->filename = strdup(filename); + + root = parse_yaml_from_file(filename); + + if (root != NULL) + { + result = g_kaitai_structure_create(kstruct, root); + g_object_unref(G_OBJECT(root)); + } + else + { + fprintf(stderr, "The provided YAML content seems invalid"); + result = false; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = lecteur de définition à initialiser pleinement. * +* parent = noeud Yaml contenant l'attribut à constituer. * +* * +* Description : Met en place un lecteur de définitions Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_structure_create(GKaitaiStruct *kstruct, GYamlNode *parent) +{ + bool result; /* Bilan à retourner */ + GYamlNode *collec; /* Liste de noeuds à traiter */ + GYamlNode **nodes; /* Eventuels noeuds trouvés */ + size_t count; /* Quantité de ces noeuds */ + size_t i; /* Boucle de parcours */ + size_t first; /* Premier emplacement dispo. */ + bool failed; /* Détection d'un échec */ + + result = false; + + /* Informations générales */ + + kstruct->meta = g_kaitai_meta_new(parent); + assert(kstruct->meta != NULL); + + result = g_kaitai_structure_load_imports(kstruct); + if (!result) goto bad_loading; + + /* Séquence */ + + collec = g_yaml_node_find_first_by_path(parent, "/seq/"); + + if (collec != NULL) + { + if (G_IS_YAML_COLLEC(collec)) + nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count); + else + count = 0; + + if (count > 0) + { + kstruct->seq_items = calloc(count, sizeof(GKaitaiAttribute *)); + kstruct->seq_items_count = count; + + for (i = 0; i < count; i++) + { + kstruct->seq_items[i] = g_kaitai_attribute_new(nodes[i]); + if (kstruct->seq_items[i] == NULL) break; + + g_object_unref(G_OBJECT(nodes[i])); + + } + + failed = (i < count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(nodes[i])); + + free(nodes); + + if (failed) + goto bad_loading; + + } + + g_object_unref(G_OBJECT(collec)); + + } + + /* Types particuliers éventuels */ + + collec = g_yaml_node_find_first_by_path(parent, "/types/"); + + if (collec != NULL) + { + if (G_IS_YAML_COLLEC(collec)) + nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count); + else + count = 0; + + if (count > 0) + { + first = kstruct->types_count; + + kstruct->types_count += count; + kstruct->types = realloc(kstruct->types, kstruct->types_count * sizeof(GKaitaiType *)); + + for (i = 0; i < count; i++) + { + kstruct->types[first + i] = g_kaitai_type_new(nodes[i]); + if (kstruct->types[first + i] == NULL) break; + + g_object_unref(G_OBJECT(nodes[i])); + + } + + failed = (i < count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(nodes[i])); + + free(nodes); + + if (failed) + goto bad_loading; + + } + + g_object_unref(G_OBJECT(collec)); + + } + + /* Instances éventuelles */ + + collec = g_yaml_node_find_first_by_path(parent, "/instances/"); + + if (collec != NULL) + { + if (G_IS_YAML_COLLEC(collec)) + nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count); + else + count = 0; + + if (count > 0) + { + kstruct->instances = calloc(count, sizeof(GKaitaiInstance *)); + kstruct->instances_count = count; + + for (i = 0; i < count; i++) + { + kstruct->instances[i] = g_kaitai_instance_new(nodes[i]); + if (kstruct->instances[i] == NULL) break; + + g_object_unref(G_OBJECT(nodes[i])); + + } + + failed = (i < count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(nodes[i])); + + free(nodes); + + if (failed) + goto bad_loading; + + } + + g_object_unref(G_OBJECT(collec)); + + } + + /* Enumérations éventuelles */ + + collec = g_yaml_node_find_first_by_path(parent, "/enums/"); + + if (collec != NULL) + { + if (G_IS_YAML_COLLEC(collec)) + nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count); + else + count = 0; + + if (count > 0) + { + kstruct->enums = calloc(count, sizeof(GKaitaiEnum *)); + kstruct->enums_count = count; + + for (i = 0; i < count; i++) + { + kstruct->enums[i] = g_kaitai_enum_new(nodes[i]); + if (kstruct->enums[i] == NULL) break; + + g_object_unref(G_OBJECT(nodes[i])); + + } + + failed = (i < count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(nodes[i])); + + free(nodes); + + if (failed) + goto bad_loading; + + } + + g_object_unref(G_OBJECT(collec)); + + } + + /* Sortie heureuse */ + + result = true; + + bad_loading: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = lecteur de définition à initialiser pleinement. * +* * +* Description : Charge les éventuelles dépendances de la définition. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_structure_load_imports(GKaitaiStruct *kstruct) +{ + bool result; /* Bilan d'opération à renvoyer*/ + const char * const *dependencies; /* Liste d'imports requis */ + size_t count; /* Quantité de ces imports */ + size_t i; /* Boucle de parcours */ + GKaitaiType *imported; /* Structure importée */ + + result = true; + + dependencies = g_kaitai_meta_get_dependencies(kstruct->meta, &count); + + for (i = 0; i < count; i++) + { + imported = import_kaitai_definition(dependencies[i], kstruct->filename); + if (imported == NULL) break; + + kstruct->types_count++; + kstruct->types = realloc(kstruct->types, kstruct->types_count * sizeof(GKaitaiType *)); + + kstruct->types[kstruct->types_count - 1] = imported; + + } + + result = (i == count); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = structure Kaitai à consulter. * +* * +* Description : Fournit la description globale d'une définition Kaitai. * +* * +* Retour : Description de la définition Kaitai courante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiMeta *g_kaitai_structure_get_meta(const GKaitaiStruct *kstruct) +{ + GKaitaiMeta *result; /* Informations à retourner */ + + result = kstruct->meta; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = structure Kaitai en cours de parcours. * +* name = désignation principale des énumérations ciblées. * +* * +* Description : Fournit un ensemble d'énumérations locales de la structure. * +* * +* Retour : Enumérations locales ou NULL si non trouvée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiEnum *g_kaitai_structure_get_enum(const GKaitaiStruct *kstruct, const sized_string_t *name) +{ + GKaitaiEnum *result; /* Instance à retourner */ + size_t i; /* Boucle de parcours */ + const char *other; /* Autre désignation à comparer*/ + + result = NULL; + + for (i = 0; i < kstruct->enums_count; i++) + { + other = g_kaitai_enum_get_name(kstruct->enums[i]); + + if (strncmp(name->data, other, name->len) == 0) // FIXME + { + result = kstruct->enums[i]; + g_object_ref(G_OBJECT(result)); + break; + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = structure Kaitai en cours de parcours. * +* name = désignation du type particulier ciblé. * +* * +* Description : Recherche la définition d'un type nouveau pour Kaitai. * +* * +* Retour : Type prêt à emploi ou NULL si non trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiType *g_kaitai_structure_find_sub_type(const GKaitaiStruct *kstruct, const char *name) +{ + GKaitaiType *result; /* Instance à retourner */ + size_t i; /* Boucle de parcours */ + const char *other; /* Autre désignation à comparer*/ + + result = NULL; + + for (i = 0; i < kstruct->types_count; i++) + { + other = g_kaitai_type_get_name(kstruct->types[i]); + + if (strcmp(name, other) == 0) + { + result = kstruct->types[i]; + g_object_ref(G_OBJECT(result)); + break; + } + + result = g_kaitai_structure_find_sub_type(G_KAITAI_STRUCT(kstruct->types[i]), name); + if (result != NULL) break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = structure Kaitai en cours de parcours. * +* content = contenu binaire en cours de traitement. * +* * +* Description : Parcourt un contenu binaire selon une description Kaitai. * +* * +* Retour : Arborescence d'éléments rencontrés selon les spécifications. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *kstruct, GBinContent *content) +{ + GMatchRecord *result; /* Arborescence à retourner */ + vmpa2t pos; /* Tête de lecture */ + kaitai_scope_t locals; /* Variables locales */ + ext_vmpa_t epos; /* Tête de lecture complète */ + + g_binary_content_compute_start_pos(content, &pos); + + init_record_scope(&locals, kstruct->meta); + + init_evmpa_from_vmpa(&epos, &pos); + + g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct), &locals, content, &epos, &result); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : kstruct = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* epos = tête de lecture courante. [OUT] * +* record = noeud d'arborescence d'éléments rencontrés. [OUT] * +* * +* Description : Parcourt un contenu binaire selon des spécifications Kaitai. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record) +{ + bool result; /* Bilan à retourner */ + GRecordGroup *group; /* Ensemble à constituer */ + GMatchRecord *old; /* Sauvegarde de valeur */ + size_t i; /* Boucle de parcours */ + GMatchRecord *child; /* Nouvel élément mis en place */ + + result = true; + + /* Si le groupe est vide */ + if ((kstruct->seq_items_count + kstruct->instances_count) == 0) + { + *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(kstruct), content, &epos->base)); + + if (locals->root == NULL) + locals->root = *record; + + } + + /* Sinon on construit selon les définitions fournies */ + else + { + group = g_record_group_new(kstruct, content); + *record = G_MATCH_RECORD(group); + + if (locals->root == NULL) + locals->root = *record; + + old = locals->parent; + locals->parent = *record; + + /** + * Les instances sont à charger avant les éléments fixes car + * des références au premières peuvent être attendues dans ces derniers. + * + * Les évolutions de la tête de lecture n'ont en revanche normalement + * pas d'incidence sur le chargement des éléments fixes. + */ + + for (i = 0; i < kstruct->instances_count; i++) + { + result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->instances[i]), + locals, content, epos, &child); + if (!result) goto exit; + + if (child != NULL) + { + g_record_group_add_record(group, child); + g_object_unref(G_OBJECT(child)); + } + + } + + /** + * Seconde phase. + */ + + locals->parent = *record; + + for (i = 0; i < kstruct->seq_items_count; i++) + { + result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->seq_items[i]), + locals, content, epos, &child); + if (!result) goto exit; + + if (child != NULL) + { + g_record_group_add_record(group, child); + g_object_unref(G_OBJECT(child)); + } + + } + + exit: + + locals->parent = old; + + if (!result) + g_clear_object(record); + + } + + return result; + +} diff --git a/plugins/kaitai/parsers/struct.h b/plugins/kaitai/parsers/struct.h new file mode 100644 index 0000000..4a2397a --- /dev/null +++ b/plugins/kaitai/parsers/struct.h @@ -0,0 +1,80 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * struct.h - prototypes pour la définition d'une structure Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_STRUCT_H +#define _PLUGINS_KAITAI_PARSERS_STRUCT_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include <analysis/content.h> + + +#include "enum.h" +#include "meta.h" +#include "type.h" +#include "../record.h" + + + +#define G_TYPE_KAITAI_STRUCT g_kaitai_structure_get_type() +#define G_KAITAI_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_STRUCT, GKaitaiStruct)) +#define G_IS_KAITAI_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_STRUCT)) +#define G_KAITAI_STRUCT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_STRUCT, GKaitaiStructClass)) +#define G_IS_KAITAI_STRUCT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_STRUCT)) +#define G_KAITAI_STRUCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_STRUCT, GKaitaiStructClass)) + + +/* Spécification d'une structure Kaitai (instance) */ +typedef struct _GKaitaiStruct GKaitaiStruct; + +/* Spécification d'une structure Kaitai (classe) */ +typedef struct _GKaitaiStructClass GKaitaiStructClass; + + +/* Indique le type défini pour une structure Kaitai. */ +GType g_kaitai_structure_get_type(void); + +/* Crée un nouvel interpréteur de structure Kaitai. */ +GKaitaiStruct *g_kaitai_structure_new_from_text(const char *); + +/* Crée un nouvel interpréteur de structure Kaitai. */ +GKaitaiStruct *g_kaitai_structure_new_from_file(const char *); + +/* Fournit la description globale d'une définition Kaitai. */ +GKaitaiMeta *g_kaitai_structure_get_meta(const GKaitaiStruct *); + +/* Recherche la définition d'un type nouveau pour Kaitai. */ +GKaitaiType *g_kaitai_structure_find_sub_type(const GKaitaiStruct *, const char *); + +/* Fournit un ensemble d'énumérations locales de la structure. */ +GKaitaiEnum *g_kaitai_structure_get_enum(const GKaitaiStruct *, const sized_string_t *); + +/* Parcourt un contenu binaire selon une description Kaitai. */ +GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *, GBinContent *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_STRUCT_H */ diff --git a/plugins/kaitai/parsers/switch-int.h b/plugins/kaitai/parsers/switch-int.h new file mode 100644 index 0000000..a087e49 --- /dev/null +++ b/plugins/kaitai/parsers/switch-int.h @@ -0,0 +1,78 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * switch-int.h - prototypes internes pour la gestion des énumérations Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_PARSERS_SWITCH_INT_H +#define PLUGINS_KAITAI_PARSERS_SWITCH_INT_H + + +#include "switch.h" +#include "../parser-int.h" + + + +/* ------------------------ BASCULE DYNAMIQUE SELON CONTEXTE ------------------------ */ + + +/* Mémorisation d'une valeur d'énumération */ +typedef struct _switch_case_t +{ + char *value; /* Valeur d'association */ + char *type; /* Désignation du type associé */ + +} switch_case_t; + + + +/* ----------------------- SELECTION DYNAMIQUE DE TYPE KAITAI ----------------------- */ + + +/* Sélection d'un type selon un contexte (instance) */ +struct _GKaitaiSwitch +{ + GKaitaiParser parent; /* A laisser en premier */ + + char *target; /* Source de bascule */ + + switch_case_t **cases; /* Choix de types potentiels */ + size_t count; /* Quantité de ces choix */ + + switch_case_t *defcase; /* Choix par défaut ou NULL */ + + GKaitaiAttribute *generic; /* Attribut à dériver */ + +}; + +/* Sélection d'un type selon un contexte (classe) */ +struct _GKaitaiSwitchClass +{ + GKaitaiParserClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une sélection dynamique de type Kaitai. */ +bool g_kaitai_switch_create(GKaitaiSwitch *, GYamlNode *, GKaitaiAttribute *); + + + +#endif /* PLUGINS_KAITAI_PARSERS_SWITCH_INT_H */ diff --git a/plugins/kaitai/parsers/switch.c b/plugins/kaitai/parsers/switch.c new file mode 100644 index 0000000..6cfc96b --- /dev/null +++ b/plugins/kaitai/parsers/switch.c @@ -0,0 +1,644 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * switch.h - gestion des énumérations Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "switch.h" + + +#include <assert.h> +#include <errno.h> +#include <malloc.h> +#include <stdlib.h> +#include <string.h> + + +#include <i18n.h> + + +#include <common/extstr.h> +#include <common/sort.h> +#include <core/logs.h> +#include <plugins/yaml/pair.h> + + +#include "switch-int.h" +#include "../expression.h" + + + +/* ------------------------ BASCULE DYNAMIQUE SELON CONTEXTE ------------------------ */ + + +/* Construit une valeur d'énumération à partir d'indications. */ +static switch_case_t *build_switch_case(const GYamlNode *, bool *); + +/* Supprime de la mémoire une bascule selon contexte. */ +static void delete_switch_case(switch_case_t *); + +/* Détermine si le cas correspond à une valeur de bascule. */ +static const char *is_suitable_switch_case_for_bytes(const switch_case_t *, const resolved_value_t *); + +/* Détermine si le cas correspond à une valeur de bascule. */ +static const char *is_suitable_switch_case_for_integer(const switch_case_t *, kaitai_scope_t *, const resolved_value_t *); + + + +/* ----------------------- SELECTION DYNAMIQUE DE TYPE KAITAI ----------------------- */ + + +/* Initialise la classe des sélections dynamiques de types. */ +static void g_kaitai_switch_class_init(GKaitaiSwitchClass *); + +/* Initialise une sélection dynamique de type Kaitai. */ +static void g_kaitai_switch_init(GKaitaiSwitch *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_switch_dispose(GKaitaiSwitch *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_switch_finalize(GKaitaiSwitch *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Parcourt un contenu binaire selon des spécifications Kaitai. */ +static bool g_kaitai_switch_parse_content(GKaitaiSwitch *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **); + + + +/* ---------------------------------------------------------------------------------- */ +/* BASCULE DYNAMIQUE SELON CONTEXTE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : node = noeud Yaml à venir lire. * +* defcase = indique si une valeur par défaut est visée. [OUT] * +* * +* Description : Construit une valeur d'énumération à partir d'indications. * +* * +* Retour : Structure de valeur mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static switch_case_t *build_switch_case(const GYamlNode *node, bool *defcase) +{ + switch_case_t *result; /* Enregistrement à retourner */ + const char *key; /* Clef d'une conversion */ + const char *value; /* Valeur Yaml particulière */ + + result = NULL; + + if (!G_IS_YAML_PAIR(node)) + goto exit; + + key = g_yaml_pair_get_key(G_YAML_PAIR(node)); + value = g_yaml_pair_get_value(G_YAML_PAIR(node)); + + if (value == NULL) + goto exit; + + result = malloc(sizeof(switch_case_t)); + + result->value = strdup(key); + result->type = strdup(value); + + *defcase = (strcmp(key, "_") == 0); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : swcase = valeur à traiter. * +* * +* Description : Supprime de la mémoire une bascule selon contexte. * +* * +* Retour : - * +* * +* Remarques : - * +* * +*****************************************************************************/ + +static void delete_switch_case(switch_case_t *swcase) +{ + free(swcase->value); + + free(swcase->type); + + free(swcase); + +} + + +/****************************************************************************** +* * +* Paramètres : swcase = valeur à analyser. * +* value = valeur à comparer. * +* * +* Description : Détermine si le cas correspond à une valeur de bascule. * +* * +* Retour : Type à utiliser ou NULL si aucune correspondance établie. * +* * +* Remarques : - * +* * +*****************************************************************************/ + +static const char *is_suitable_switch_case_for_bytes(const switch_case_t *swcase, const resolved_value_t *value) +{ + const char *result; /* Désignation à retourner */ + sized_string_t key; /* Changement de format */ + bool valid; /* Validité des opérations */ + int ret; /* Bilan d'une comparaison */ + + result = NULL; + + key.data = swcase->value; + key.len = strlen(swcase->value); + + valid = (key.len > 2); + + if (valid) + valid = (swcase->value[0] == '"' || swcase->value[0] == '\''); + + if (valid) + { + valid = (key.data[0] == key.data[key.len - 1]); + + key.data++; + key.len -= 2; + + } + + if (valid) + { + if (value->type == GVT_BYTES) + { + ret = szmemcmp(&key, &value->bytes); + + if (ret == 0) + result = swcase->type; + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : swcase = valeur à analyser. * +* locals = variables locales pour les résolutions de types. * +* value = valeur à comparer. * +* * +* Description : Détermine si le cas correspond à une valeur de bascule. * +* * +* Retour : Type à utiliser ou NULL si aucune correspondance établie. * +* * +* Remarques : - * +* * +*****************************************************************************/ + +static const char *is_suitable_switch_case_for_integer(const switch_case_t *swcase, kaitai_scope_t *locals, const resolved_value_t *value) +{ + const char *result; /* Désignation à retourner */ + bool valid; /* Validité des opérations */ + resolved_value_t key; /* Changement de format */ + unsigned long long unsigned_conv; /* Valeur convertie #1 */ + long long signed_conv; /* Valeur convertie #2 */ + + result = NULL; + + valid = (swcase->value[0] != '"' && swcase->value[0] != '\''); + + if (valid) + { + if (strchr(swcase->value, ':') != NULL) + { + valid = resolve_kaitai_expression_as_integer(locals, swcase->value, strlen(swcase->value), &key); + + if (valid) + { + if (key.type == GVT_UNSIGNED_INTEGER) + { + if (value->type == GVT_UNSIGNED_INTEGER) + { + if (key.unsigned_integer == value->unsigned_integer) + result = swcase->type; + } + else + { + if (key.unsigned_integer == value->signed_integer) + result = swcase->type; + } + } + else + { + if (value->type == GVT_UNSIGNED_INTEGER) + { + if (key.signed_integer == value->unsigned_integer) + result = swcase->type; + } + else + { + if (key.signed_integer == value->signed_integer) + result = swcase->type; + } + } + + } + + } + + else + { + if (value->type == GVT_UNSIGNED_INTEGER) + { + unsigned_conv = strtoull(swcase->value, NULL, 0); + + valid = (errno != ERANGE && errno != EINVAL); + + if (valid && unsigned_conv == value->unsigned_integer) + result = swcase->type; + + } + else + { + signed_conv = strtoll(swcase->value, NULL, 0); + + valid = (errno != ERANGE && errno != EINVAL); + + if (valid && signed_conv == value->signed_integer) + result = swcase->type; + + } + + } + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* SELECTION DYNAMIQUE DE TYPE KAITAI */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un choix dynamique de type Kaitai. */ +G_DEFINE_TYPE(GKaitaiSwitch, g_kaitai_switch, G_TYPE_KAITAI_PARSER); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des sélections dynamiques de types. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_switch_class_init(GKaitaiSwitchClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GKaitaiParserClass *parser; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_switch_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_switch_finalize; + + parser = G_KAITAI_PARSER_CLASS(klass); + + parser->parse = (parse_kaitai_fc)g_kaitai_switch_parse_content; + +} + + +/****************************************************************************** +* * +* Paramètres : kswitch = instance à initialiser. * +* * +* Description : Initialise une sélection dynamique de type Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_switch_init(GKaitaiSwitch *kswitch) +{ + kswitch->target = NULL; + + kswitch->cases = NULL; + kswitch->count = 0; + + kswitch->defcase = NULL; + + kswitch->generic = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : kswitch = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_switch_dispose(GKaitaiSwitch *kswitch) +{ + g_clear_object(&kswitch->generic); + + G_OBJECT_CLASS(g_kaitai_switch_parent_class)->dispose(G_OBJECT(kswitch)); + +} + + +/****************************************************************************** +* * +* Paramètres : kswitch = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_switch_finalize(GKaitaiSwitch *kswitch) +{ + size_t i; /* Boucle de parcours */ + + if (kswitch->target != NULL) + free(kswitch->target); + + for (i = 0; i < kswitch->count; i++) + delete_switch_case(kswitch->cases[i]); + + if (kswitch->cases != NULL) + free(kswitch->cases); + + if (kswitch->defcase != NULL) + delete_switch_case(kswitch->defcase); + + G_OBJECT_CLASS(g_kaitai_switch_parent_class)->finalize(G_OBJECT(kswitch)); + +} + + +/****************************************************************************** +* * +* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. * +* generic = lecteur d'attribut Kaitai à dériver. * +* * +* Description : Construit une sélection dynamique de type Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiSwitch *g_kaitai_switch_new(GYamlNode *parent, GKaitaiAttribute *generic) +{ + GKaitaiSwitch *result; /* Identifiant à retourner */ + + result = g_object_new(G_TYPE_KAITAI_SWITCH, NULL); + + if (!g_kaitai_switch_create(result, parent, generic)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : kswitch = sélectionneur de type à initialiser pleinement. * +* parent = noeud Yaml contenant l'attribut à constituer. * +* generic = lecteur d'attribut Kaitai à dériver. * +* * +* Description : Met en place une sélection dynamique de type Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_switch_create(GKaitaiSwitch *kswitch, GYamlNode *parent, GKaitaiAttribute *generic) +{ + bool result; /* Bilan à retourner */ + GYamlNode *node; /* Noeud de définition */ + GYamlNode *subnode; /* Noeud de précisions */ + const char *value; /* Valeur Yaml particulière */ + GYamlNode *collec; /* Liste de noeuds à traiter */ + GYamlNode **subnodes; /* Eventuels noeuds trouvés */ + size_t count; /* Quantité de ces noeuds */ + size_t i; /* Boucle de parcours */ + bool defcase; /* Définition par défaut ? */ + switch_case_t *swcase; /* Bascule à noter */ + + result = false; + + node = g_yaml_node_find_first_by_path(parent, "/type/"); + if (node == NULL) goto exit; + + /* Source de la bascule */ + + subnode = g_yaml_node_find_first_by_path(node, "/switch-on"); + assert(G_IS_YAML_PAIR(subnode)); + + value = g_yaml_pair_get_value(G_YAML_PAIR(subnode)); + if (value == NULL) + { + g_object_unref(G_OBJECT(subnode)); + goto bad_definition; + } + + kswitch->target = strdup(value); + + g_object_unref(G_OBJECT(subnode)); + + /* Conditions de bascule */ + + collec = g_yaml_node_find_first_by_path(node, "/cases/"); + if (collec == NULL) goto bad_definition; + if (!G_IS_YAML_COLLEC(collec)) goto bad_definition; + + subnodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count); + + g_object_unref(G_OBJECT(collec)); + + if (count == 0) goto bad_definition; + + for (i = 0; i < count; i++) + { + swcase = build_switch_case(subnodes[i], &defcase); + if (swcase == NULL) break; + + g_object_unref(G_OBJECT(subnodes[i])); + + kswitch->cases = realloc(kswitch->cases, ++kswitch->count * sizeof(switch_case_t *)); + kswitch->cases[kswitch->count - 1] = swcase; + + } + + result = (i == count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(subnodes[i])); + + if (subnodes != NULL) + free(subnodes); + + /* Fin des procédures */ + + if (result) + { + kswitch->generic = generic; + g_object_ref(G_OBJECT(generic)); + } + + bad_definition: + + g_object_unref(G_OBJECT(node)); + + exit: + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : kswitch = structure Kaitai en cours de parcours. * +* locals = variables locales pour les résolutions de types. * +* content = données binaires à analyser et traduire. * +* epos = tête de lecture courante. [OUT] * +* record = noeud d'arborescence d'éléments rencontrés. [OUT] * +* * +* Description : Parcourt un contenu binaire selon des spécifications Kaitai. * +* * +* Retour : Bilan de l'opératon : true pour continuer, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_switch_parse_content(GKaitaiSwitch *kswitch, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record) +{ + bool result; /* Bilan à retourner */ + const char *final_type; /* Type à utiliser au final */ + resolved_value_t value; /* Valeur de cible entière */ + bool status; /* Bilan intermédiaire */ + size_t i; /* Boucle de parcours */ + GKaitaiAttribute *attrib; /* Lecteur approprié */ + + result = true; + + final_type = NULL; + + /* Tenative n°1 : version "entier" */ + + status = resolve_kaitai_expression_as_integer(locals, kswitch->target, strlen(kswitch->target), &value); + + if (status) + for (i = 0; i < kswitch->count; i++) + { + final_type = is_suitable_switch_case_for_integer(kswitch->cases[i], locals, &value); + + if (final_type != NULL) + goto next_step; + + } + + status = resolve_kaitai_expression_as_bytes(locals, kswitch->target, strlen(kswitch->target), &value); + + /* Tenative n°1 : version "chaîne" */ + + if (status) + for (i = 0; i < kswitch->count; i++) + { + final_type = is_suitable_switch_case_for_bytes(kswitch->cases[i], &value); + + if (final_type != NULL) + goto next_step; + + } + + if (final_type == NULL && kswitch->defcase != NULL) + final_type = kswitch->defcase->type; + + next_step: + + /* Mise en place d'un attribut et analyse */ + + if (final_type != NULL) + { + attrib = g_kaitai_attribute_dup_for_user_type(kswitch->generic, final_type); + + result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib), locals, content, epos, record); + + g_object_unref(G_OBJECT(attrib)); + + } + + return true; + return result; + +} diff --git a/plugins/kaitai/parsers/switch.h b/plugins/kaitai/parsers/switch.h new file mode 100644 index 0000000..c45237a --- /dev/null +++ b/plugins/kaitai/parsers/switch.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * switch.h - prototypes pour la gestion des énumérations Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_SWITCH_H +#define _PLUGINS_KAITAI_PARSERS_SWITCH_H + + +#include <glib-object.h> + + +#include <plugins/yaml/node.h> + + +#include "attribute.h" + + + +#define G_TYPE_KAITAI_SWITCH g_kaitai_switch_get_type() +#define G_KAITAI_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_SWITCH, GKaitaiSwitch)) +#define G_IS_KAITAI_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_SWITCH)) +#define G_KAITAI_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_SWITCH, GKaitaiSwitchClass)) +#define G_IS_KAITAI_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_SWITCH)) +#define G_KAITAI_SWITCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_SWITCH, GKaitaiSwitchClass)) + + +/* Sélection d'un type selon un contexte (instance) */ +typedef struct _GKaitaiSwitch GKaitaiSwitch; + +/* Sélection d'un type selon un contexte (classe) */ +typedef struct _GKaitaiSwitchClass GKaitaiSwitchClass; + + +/* Indique le type défini pour un choix dynamique de type Kaitai. */ +GType g_kaitai_switch_get_type(void); + +/* Construit une sélection dynamique de type Kaitai. */ +GKaitaiSwitch *g_kaitai_switch_new(GYamlNode *, GKaitaiAttribute *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_SWITCH_H */ diff --git a/plugins/kaitai/parsers/type-int.h b/plugins/kaitai/parsers/type-int.h new file mode 100644 index 0000000..535ce57 --- /dev/null +++ b/plugins/kaitai/parsers/type-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type-int.h - prototypes internes pour la définition d'un type particulier pour Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_PARSERS_TYPE_INT_H +#define PLUGINS_KAITAI_PARSERS_TYPE_INT_H + + +#include "struct-int.h" +#include "type.h" + + + +/* Définition d'un type particulier nouveau pour Kaitai (instance) */ +struct _GKaitaiType +{ + GKaitaiStruct parent; /* A laisser en premier */ + + char *name; /* Nom du type particulier */ + +}; + +/* Définition d'un type particulier nouveau pour Kaitai (classe) */ +struct _GKaitaiTypeClass +{ + GKaitaiStructClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un lecteur de type pour Kaitai. */ +bool g_kaitai_type_create(GKaitaiType *, GYamlNode *); + +/* Met en place un lecteur de type externe pour Kaitai. */ +bool g_kaitai_type_create_as_import(GKaitaiType *, const char *, const char *); + + + +#endif /* PLUGINS_KAITAI_PARSERS_TYPE_INT_H */ diff --git a/plugins/yaml/reader.c b/plugins/kaitai/parsers/type.c index eebc02b..81efbeb 100644 --- a/plugins/yaml/reader.c +++ b/plugins/kaitai/parsers/type.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * reader.c - lecteur de contenu Yaml + * struct.c - définition d'une structure Kaitai * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019 Cyrille Bagard * * This file is part of Chrysalide. * @@ -21,61 +21,42 @@ */ -#include "reader.h" +#include "type.h" #include <malloc.h> #include <string.h> -#include <gio/gio.h> +#include <plugins/yaml/pair.h> -#include "line.h" +#include "type-int.h" +#include "../parser.h" -/* Lecteur de contenu Yaml (instance) */ -struct _GYamlReader -{ - GObject parent; /* A laisser en premier */ - - GYamlLine **lines; /* Lignes Yaml chargées */ - size_t count; /* Quantié de ces lignes */ - - GYamlTree *tree; /* Arborescence constituée */ - -}; - -/* Lecteur de contenu Yaml (classe) */ -struct _GYamlReaderClass -{ - GObjectClass parent; /* A laisser en premier */ +/* Initialise la classe des types particuliers pour Kaitai. */ +static void g_kaitai_type_class_init(GKaitaiTypeClass *); -}; - - -/* Initialise la classe des lecteurs de contenus Yaml. */ -static void g_yaml_reader_class_init(GYamlReaderClass *); - -/* Initialise une instance de lecteur de contenu Yaml. */ -static void g_yaml_reader_init(GYamlReader *); +/* Initialise un type particulier pour Kaitai. */ +static void g_kaitai_type_init(GKaitaiType *); /* Supprime toutes les références externes. */ -static void g_yaml_reader_dispose(GYamlReader *); +static void g_kaitai_type_dispose(GKaitaiType *); /* Procède à la libération totale de la mémoire. */ -static void g_yaml_reader_finalize(GYamlReader *); +static void g_kaitai_type_finalize(GKaitaiType *); -/* Indique le type défini pour un lecteur de contenu Yaml. */ -G_DEFINE_TYPE(GYamlReader, g_yaml_reader, G_TYPE_OBJECT); +/* Indique le type défini pour un type particulier pour Kaitai. */ +G_DEFINE_TYPE(GKaitaiType, g_kaitai_type, G_TYPE_KAITAI_STRUCT); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des lecteurs de contenus Yaml. * +* Description : Initialise la classe des types particuliers pour Kaitai. * * * * Retour : - * * * @@ -83,23 +64,23 @@ G_DEFINE_TYPE(GYamlReader, g_yaml_reader, G_TYPE_OBJECT); * * ******************************************************************************/ -static void g_yaml_reader_class_init(GYamlReaderClass *klass) +static void g_kaitai_type_class_init(GKaitaiTypeClass *klass) { GObjectClass *object; /* Autre version de la classe */ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_reader_dispose; - object->finalize = (GObjectFinalizeFunc)g_yaml_reader_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_type_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_type_finalize; } /****************************************************************************** * * -* Paramètres : reader = instance à initialiser. * +* Paramètres : kstruct = instance à initialiser. * * * -* Description : Initialise une instance de lecteur de contenu Yaml. * +* Description : Initialise un type particulier pour Kaitai. * * * * Retour : - * * * @@ -107,19 +88,16 @@ static void g_yaml_reader_class_init(GYamlReaderClass *klass) * * ******************************************************************************/ -static void g_yaml_reader_init(GYamlReader *reader) +static void g_kaitai_type_init(GKaitaiType *type) { - reader->lines = NULL; - reader->count = 0; - - reader->tree = NULL; + type->name = NULL; } /****************************************************************************** * * -* Paramètres : reader = instance d'objet GLib à traiter. * +* Paramètres : type = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -129,23 +107,16 @@ static void g_yaml_reader_init(GYamlReader *reader) * * ******************************************************************************/ -static void g_yaml_reader_dispose(GYamlReader *reader) +static void g_kaitai_type_dispose(GKaitaiType *type) { - size_t i; /* Boucle de parcours */ - - for (i = 0; i < reader->count; i++) - g_clear_object(&reader->lines[i]); - - g_clear_object(&reader->tree); - - G_OBJECT_CLASS(g_yaml_reader_parent_class)->dispose(G_OBJECT(reader)); + G_OBJECT_CLASS(g_kaitai_type_parent_class)->dispose(G_OBJECT(type)); } /****************************************************************************** * * -* Paramètres : reader = instance d'objet GLib à traiter. * +* Paramètres : type = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -155,22 +126,21 @@ static void g_yaml_reader_dispose(GYamlReader *reader) * * ******************************************************************************/ -static void g_yaml_reader_finalize(GYamlReader *reader) +static void g_kaitai_type_finalize(GKaitaiType *type) { - if (reader->lines != NULL) - free(reader->lines); + if (type->name != NULL) + free(type->name); - G_OBJECT_CLASS(g_yaml_reader_parent_class)->finalize(G_OBJECT(reader)); + G_OBJECT_CLASS(g_kaitai_type_parent_class)->finalize(G_OBJECT(type)); } /****************************************************************************** * * -* Paramètres : content = données brutes au format Yaml à charger. * -* length = quantité de ces données. * +* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. * * * -* Description : Crée un lecteur pour contenu au format Yaml. * +* Description : Construit un lecteur de type pour Kaitai. * * * * Retour : Instance mise en place ou NULL en cas d'échec. * * * @@ -178,135 +148,92 @@ static void g_yaml_reader_finalize(GYamlReader *reader) * * ******************************************************************************/ -GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length) +GKaitaiType *g_kaitai_type_new(GYamlNode *parent) { - GYamlReader *result; /* Structure à retourner */ - char *dumped; /* Contenu manipulable */ - char *saved; /* Sauvegarde de position */ - char *iter; /* Boucle de parcours */ - size_t number; /* Indice de ligne courante */ - GYamlLine *line; /* Nouvelle ligne Yaml */ - - result = g_object_new(G_TYPE_YAML_READER, NULL); - - dumped = malloc(length * sizeof(char)); - - memcpy(dumped, content, length); - - for (iter = dumped, saved = strchr(iter, '\n'), number = 0; - *iter != '\0'; - iter = ++saved, saved = strchr(iter, '\n'), number++) - { - if (saved != NULL) - *saved = '\0'; - - if (*iter != '\0') - { - line = g_yaml_line_new(iter, number); - - if (line == NULL) - goto format_error; - - result->lines = realloc(result->lines, ++result->count * sizeof(GYamlLine *)); - - g_object_ref_sink(G_OBJECT(line)); - result->lines[result->count - 1] = line; - - } - - if (saved == NULL) - break; + GKaitaiType *result; /* Structure à retourner */ - } + result = g_object_new(G_TYPE_KAITAI_TYPE, NULL); - free(dumped); - - result->tree = g_yaml_tree_new(result->lines, result->count); + if (!g_kaitai_type_create(result, parent)) + g_clear_object(&result); return result; - format_error: - - g_object_unref(G_OBJECT(result)); - - return NULL; - } /****************************************************************************** * * -* Paramètres : path = chemin d'accès à un contenu à charger. * +* Paramètres : type = lecteur de type Kaitai à initialiser pleinement. * +* parent = noeud Yaml contenant l'attribut à constituer. * * * -* Description : Crée un lecteur pour contenu au format Yaml. * +* Description : Met en place un lecteur de type pour Kaitai. * * * -* Retour : Instance mise en place ou NULL en cas d'échec. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -GYamlReader *g_yaml_reader_new_from_path(const char *path) +bool g_kaitai_type_create(GKaitaiType *type, GYamlNode *parent) { - GYamlReader *result; /* Structure à retourner */ - char *scheme; /* Préfixe d'URI identifié */ - GFile *file; /* Accès au contenu visé */ - GFileInputStream *stream; /* Flux ouvert en lecture */ - GFileInfo *info; /* Informations du flux */ - size_t length; /* Quantité d'octets présents */ - char *content; /* Données obtenues par lecture*/ - - result = NULL; + bool result; /* Bilan à retourner */ + const char *name; /* Désignation du type */ + char *sub_path; /* Chemin d'accès suivant */ + GYamlNode *sub; /* Contenu Yaml d'un type */ - /* Ouverture du fichier */ + result = false; - scheme = g_uri_parse_scheme(path); + /* Extraction du nom */ - if (scheme != NULL) - { - g_free(scheme); - file = g_file_new_for_uri(path); - } + if (!G_IS_YAML_PAIR(parent)) + goto exit; - else - file = g_file_new_for_path(path); + name = g_yaml_pair_get_key(G_YAML_PAIR(parent)); - stream = g_file_read(file, NULL, NULL); + type->name = strdup(name); - if (stream == NULL) - goto no_content; + /* Extraction des bases du type */ - /* Détermination de sa taille */ + asprintf(&sub_path, "/%s/", name); + sub = g_yaml_node_find_first_by_path(parent, sub_path); + free(sub_path); - info = g_file_input_stream_query_info(stream, G_FILE_ATTRIBUTE_STANDARD_SIZE, NULL, NULL); + if (sub == NULL) + goto exit; - if (info == NULL) - goto no_size_info; + result = g_kaitai_structure_create(G_KAITAI_STRUCT(type), sub); - length = g_file_info_get_size(info); + g_object_unref(G_OBJECT(sub)); - /* Lecture des données */ + exit: - content = malloc(length + 1 * sizeof(char)); - - if (!g_input_stream_read_all(G_INPUT_STREAM(stream), content, length, (gsize []) { 0 }, NULL, NULL)) - goto read_error; - - content[length] = '\0'; - - result = g_yaml_reader_new_from_content(content, length + 1); + return result; - read_error: +} - free(content); - no_size_info: +/****************************************************************************** +* * +* Paramètres : name = nom à attribuer au futur type. * +* filename = chemin vers une définition Kaitai à charger. * +* * +* Description : Construit un lecteur de type externe pour Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ - g_object_unref(G_OBJECT(stream)); +GKaitaiType *g_kaitai_type_new_as_import(const char *name, const char *filename) +{ + GKaitaiType *result; /* Structure à retourner */ - no_content: + result = g_object_new(G_TYPE_KAITAI_TYPE, NULL); - g_object_unref(G_OBJECT(file)); + if (!g_kaitai_type_create_as_import(result, name, filename)) + g_clear_object(&result); return result; @@ -315,31 +242,29 @@ GYamlReader *g_yaml_reader_new_from_path(const char *path) /****************************************************************************** * * -* Paramètres : reader = lecteur de contenu Yaml à consulter. * -* count = taille de la liste constituée. [OUT] * +* Paramètres : type = lecteur de type Kaitai à initialiser pleinement. * +* name = nom à attribuer au futur type. * +* filename = chemin vers une définition Kaitai à charger. * * * -* Description : Fournit la liste des lignes lues depuis un contenu Yaml. * +* Description : Met en place un lecteur de type externe pour Kaitai. * * * -* Retour : Liste de lignes correspondant au contenu Yaml lu. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -GYamlLine **g_yaml_reader_get_lines(const GYamlReader *reader, size_t *count) +bool g_kaitai_type_create_as_import(GKaitaiType *type, const char *name, const char *filename) { - GYamlLine **result; /* Liste à retourner */ - size_t i; /* Boucle de parcours */ + bool result; /* Bilan à retourner */ - *count = reader->count; + /* Extraction du nom */ - result = malloc(*count * sizeof(GYamlLine *)); + type->name = strdup(name); - for (i = 0; i < *count; i++) - { - result[i] = reader->lines[i]; - g_object_ref(result[i]); - } + /* Extraction des bases du type */ + + result = g_kaitai_structure_create_from_file(G_KAITAI_STRUCT(type), filename); return result; @@ -348,24 +273,21 @@ GYamlLine **g_yaml_reader_get_lines(const GYamlReader *reader, size_t *count) /****************************************************************************** * * -* Paramètres : reader = lecteur de contenu Yaml à consulter. * +* Paramètres : type = définition de type particulier à consulter. * * * -* Description : Fournit l'arborescence associée à la lecture de lignes Yaml. * +* Description : Indique le nom de scène du type représenté. * * * -* Retour : Arborescence constituée par la lecture du contenu Yaml. * +* Retour : Désignation humaine. * * * * Remarques : - * * * ******************************************************************************/ -GYamlTree *g_yaml_reader_get_tree(const GYamlReader *reader) +const char *g_kaitai_type_get_name(const GKaitaiType *type) { - GYamlTree *result; /* Arborescence à retourner */ - - result = reader->tree; + const char *result; /* Nom à retourner */ - if (result != NULL) - g_object_ref(G_OBJECT(result)); + result = type->name; return result; diff --git a/plugins/kaitai/parsers/type.h b/plugins/kaitai/parsers/type.h new file mode 100644 index 0000000..d19ab90 --- /dev/null +++ b/plugins/kaitai/parsers/type.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.h - prototypes pour la définition d'un type particulier pour Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_PARSERS_TYPE_H +#define _PLUGINS_KAITAI_PARSERS_TYPE_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include <plugins/yaml/node.h> + + + +#define G_TYPE_KAITAI_TYPE g_kaitai_type_get_type() +#define G_KAITAI_TYPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_TYPE, GKaitaiType)) +#define G_IS_KAITAI_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_TYPE)) +#define G_KAITAI_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_TYPE, GKaitaiTypeClass)) +#define G_IS_KAITAI_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_TYPE)) +#define G_KAITAI_TYPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_TYPE, GKaitaiTypeClass)) + + +/* Définition d'un type particulier nouveau pour Kaitai (instance) */ +typedef struct _GKaitaiType GKaitaiType; + +/* Définition d'un type particulier nouveau pour Kaitai (classe) */ +typedef struct _GKaitaiTypeClass GKaitaiTypeClass; + + +/* Indique le type défini pour un type particulier pour Kaitai. */ +GType g_kaitai_type_get_type(void); + +/* Construit un lecteur de type pour Kaitai. */ +GKaitaiType *g_kaitai_type_new(GYamlNode *); + +/* Construit un lecteur de type externe pour Kaitai. */ +GKaitaiType *g_kaitai_type_new_as_import(const char *, const char *); + +/* Indique le nom de scène du type représenté. */ +const char *g_kaitai_type_get_name(const GKaitaiType *); + + + +#endif /* _PLUGINS_KAITAI_PARSERS_TYPE_H */ diff --git a/plugins/kaitai/python/Makefile.am b/plugins/kaitai/python/Makefile.am new file mode 100644 index 0000000..f222a66 --- /dev/null +++ b/plugins/kaitai/python/Makefile.am @@ -0,0 +1,26 @@ + +noinst_LTLIBRARIES = libkaitaipython.la + +libkaitaipython_la_SOURCES = \ + array.h array.c \ + module.h module.c \ + parser.h parser.c \ + record.h record.c \ + scope.h scope.c \ + stream.h stream.c + +libkaitaipython_la_LIBADD = \ + parsers/libkaitaipythonparsers.la \ + records/libkaitaipythonrecords.la \ + rost/libkaitaipythonrost.la + +libkaitaipython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaipython_la_SOURCES:%c=) + + +SUBDIRS = parsers records rost diff --git a/plugins/kaitai/python/array.c b/plugins/kaitai/python/array.c new file mode 100644 index 0000000..4973c76 --- /dev/null +++ b/plugins/kaitai/python/array.c @@ -0,0 +1,265 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * array.h - équivalent Python du fichier "plugins/kaitai/array.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "array.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../array-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_array, G_TYPE_KAITAI_ARRAY); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_array_init(PyObject *, PyObject *, PyObject *); + +/* Convertit un tableau Kaitai en série d'octets si possible. */ +static PyObject *py_kaitai_array___bytes__(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_array_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define KAITAI_ARRAY_DOC \ + "KaitaiArray defines an array for collecting various Kaitai items." \ + "\n" \ + "Instances can be created using following constructor:\n" \ + "\n" \ + " KaitaiArray()" \ + "\n" \ + "In this implementation, arrays do not have to carry items all" \ + " belonging to the same type. Access and conversions to bytes are" \ + " handled and checked at runtime." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un binaire. * +* args = arguments fournis à l'appel. * +* * +* Description : Convertit un tableau Kaitai en série d'octets si possible. * +* * +* Retour : Série d'octets ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_array___bytes__(PyObject *self, PyObject *args) +{ + PyObject *result; /* Représentation à renvoyer */ + GKaitaiArray *array; /* Tableau à manipuler */ + sized_string_t bytes; /* Version en série d'octets */ + bool status; /* Bilan de la conversion */ + +#define KAITAI_ARRAY_AS_BYTES_METHOD PYTHON_METHOD_DEF \ +( \ + __bytes__, "$self, /", \ + METH_NOARGS, py_kaitai_array, \ + "Provide a bytes representation of the array, when possible" \ + " and without implementing the Python buffer protocol.\n" \ + "\n" \ + "THe result is bytes or a *TypeError* exception is raised if" \ + " the array is not suitable for a conversion to bytes." \ +) + + array = G_KAITAI_ARRAY(pygobject_get(self)); + + status = g_kaitai_array_convert_to_bytes(array, &bytes); + + if (status) + { + result = PyBytes_FromStringAndSize(bytes.data, bytes.len); + exit_szstr(&bytes); + } + else + { + PyErr_SetString(PyExc_TypeError, "unable to convert the Kaitai array to bytes"); + result = NULL; + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_array_type(void) +{ + static PyMethodDef py_kaitai_array_methods[] = { + KAITAI_ARRAY_AS_BYTES_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_array_getseters[] = { + { NULL } + }; + + static PyTypeObject py_kaitai_array_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiArray", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_ARRAY_DOC, + + .tp_methods = py_kaitai_array_methods, + .tp_getset = py_kaitai_array_getseters, + + .tp_init = py_kaitai_array_init, + .tp_new = py_kaitai_array_new, + + }; + + return &py_kaitai_array_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiArray. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_array_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiArray' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_array_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ARRAY, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en tableau d'éléments Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_array(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_array_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai array"); + break; + + case 1: + *((GKaitaiArray **)dst) = G_KAITAI_ARRAY(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/array.h b/plugins/kaitai/python/array.h new file mode 100644 index 0000000..aeba541 --- /dev/null +++ b/plugins/kaitai/python/array.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * array.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/array.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_ARRAY_H +#define _PLUGINS_KAITAI_PYTHON_ARRAY_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_array_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiArray'. */ +bool ensure_python_kaitai_array_is_registered(void); + +/* Tente de convertir en tableau d'éléments Kaitai. */ +int convert_to_kaitai_array(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_ARRAY_H */ diff --git a/plugins/kaitai/python/module.c b/plugins/kaitai/python/module.c new file mode 100644 index 0000000..07fb962 --- /dev/null +++ b/plugins/kaitai/python/module.c @@ -0,0 +1,135 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire kaitai en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "array.h" +#include "parser.h" +#include "record.h" +#include "scope.h" +#include "stream.h" +#include "parsers/module.h" +#include "records/module.h" +#include "rost/module.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.kaitai' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_module_to_python_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_KAITAI_DOC \ + "kaitai is a module trying to reverse some of the effects produced by ProGuard.\n" \ + "\n" \ + "Its action is focused on reverting name obfuscation by running binary diffing against" \ + " OpenSource packages from the AOSP." + + static PyModuleDef py_chrysalide_kaitai_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.kaitai", + .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins"); + + module = build_python_module(super, &py_chrysalide_kaitai_module); + + result = (module != NULL); + + assert(result); + + if (result) result = add_kaitai_parsers_module(); + if (result) result = add_kaitai_records_module(); + if (result) result = add_kaitai_rost_module(); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.kaitai'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_kaitai_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_kaitai_array_is_registered(); + if (result) result = ensure_python_kaitai_parser_is_registered(); + if (result) result = ensure_python_match_record_is_registered(); + if (result) result = ensure_python_kaitai_scope_is_registered(); + if (result) result = ensure_python_kaitai_stream_is_registered(); + + if (result) result = populate_kaitai_parsers_module(); + if (result) result = populate_kaitai_records_module(); + if (result) result = populate_kaitai_rost_module(); + + assert(result); + + return result; + +} diff --git a/plugins/kaitai/python/module.h b/plugins/kaitai/python/module.h new file mode 100644 index 0000000..939de07 --- /dev/null +++ b/plugins/kaitai/python/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire kaitai en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_MODULE_H +#define _PLUGINS_KAITAI_PYTHON_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.kaitai' au module Python. */ +bool add_kaitai_module_to_python_module(void); + +/* Intègre les objets du module 'plugins.kaitai'. */ +bool populate_kaitai_module(void); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_MODULE_H */ diff --git a/plugins/kaitai/python/parser.c b/plugins/kaitai/python/parser.c new file mode 100644 index 0000000..067d3b0 --- /dev/null +++ b/plugins/kaitai/python/parser.c @@ -0,0 +1,205 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.h - équivalent Python du fichier "plugins/kaitai/parser.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "parser.h" + + +#include <pygobject.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../parser.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(kaitai_parser, G_TYPE_KAITAI_PARSER, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_parser_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_parser_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define KAITAI_PARSER_DOC \ + "KaitaiParser is the class providing support for parsing binary contents" \ + " using a special declarative language." \ + "\n" \ + "It is the Python bindings for a C implementation of the specifications" \ + " described at http://kaitai.io/." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_parser_type(void) +{ + static PyMethodDef py_kaitai_parser_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_parser_getseters[] = { + { NULL } + }; + + static PyTypeObject py_kaitai_parser_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiParser", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_PARSER_DOC, + + .tp_methods = py_kaitai_parser_methods, + .tp_getset = py_kaitai_parser_getseters, + + .tp_init = py_kaitai_parser_init, + .tp_new = py_kaitai_parser_new, + + }; + + return &py_kaitai_parser_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiParser.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_parser_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiParser' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_parser_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_PARSER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en lecteur de données Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_parser(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_parser_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai parser"); + break; + + case 1: + *((GKaitaiParser **)dst) = G_KAITAI_PARSER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/yaml/python/reader.h b/plugins/kaitai/python/parser.h index 19d238b..f4b6c96 100644 --- a/plugins/yaml/python/reader.h +++ b/plugins/kaitai/python/parser.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * reader.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/reader.h" + * parser.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parser.h" * * Copyright (C) 2019 Cyrille Bagard * @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_YAML_PYTHON_READER_H -#define _PLUGINS_YAML_PYTHON_READER_H +#ifndef _PLUGINS_KAITAI_PYTHON_PARSER_H +#define _PLUGINS_KAITAI_PYTHON_PARSER_H #include <Python.h> @@ -32,14 +32,14 @@ /* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_yaml_reader_type(void); +PyTypeObject *get_python_kaitai_parser_type(void); -/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlReader'. */ -bool register_python_yaml_reader(PyObject *); +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiParser'. */ +bool ensure_python_kaitai_parser_is_registered(void); -/* Tente de convertir en lecteur de données au format Yaml. */ -int convert_to_yaml_reader(PyObject *, void *); +/* Tente de convertir en lecteur de données Kaitai. */ +int convert_to_kaitai_parser(PyObject *, void *); -#endif /* _PLUGINS_YAML_PYTHON_READER_H */ +#endif /* _PLUGINS_KAITAI_PYTHON_PARSER_H */ diff --git a/plugins/kaitai/python/parsers/Makefile.am b/plugins/kaitai/python/parsers/Makefile.am new file mode 100644 index 0000000..4c418af --- /dev/null +++ b/plugins/kaitai/python/parsers/Makefile.am @@ -0,0 +1,19 @@ + +noinst_LTLIBRARIES = libkaitaipythonparsers.la + +libkaitaipythonparsers_la_SOURCES = \ + attribute.h attribute.c \ + enum.h enum.c \ + instance.h instance.c \ + meta.h meta.c \ + module.h module.c \ + struct.h struct.c \ + type.h type.c + +libkaitaipythonparsers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaipythonparsers_la_SOURCES:%c=) diff --git a/plugins/kaitai/python/parsers/attribute.c b/plugins/kaitai/python/parsers/attribute.c new file mode 100644 index 0000000..c2f3db6 --- /dev/null +++ b/plugins/kaitai/python/parsers/attribute.c @@ -0,0 +1,425 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * attribute.c - équivalent Python du fichier "plugins/kaitai/parsers/attribute.c" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "attribute.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "../parser.h" +#include "../../parsers/attribute-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_attribute, G_TYPE_KAITAI_ATTRIBUTE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_attribute_init(PyObject *, PyObject *, PyObject *); + +/* Indique la désignation brute d'un identifiant Kaitai. */ +static PyObject *py_kaitai_attribute_get_raw_id(PyObject *, void *); + +/* Indique la désignation originelle d'un identifiant Kaitai. */ +static PyObject *py_kaitai_attribute_get_original_id(PyObject *, void *); + +/* Fournit une éventuelle documentation concernant l'attribut. */ +static PyObject *py_kaitai_attribute_get_doc(PyObject *, void *); + +/* Détermine si l'attribue porte une valeur entière signée. */ +static PyObject *py_kaitai_attribute_get_handle_signed_integer(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_attribute_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiAttribute *attrib; /* Création GLib à transmettre */ + +#define KAITAI_ATTRIBUTE_DOC \ + "KaitaiAttribute is the class providing support for parsing binary" \ + " contents using a special declarative language." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiAttribute(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the Attribute" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + if (!g_kaitai_attribute_create(attrib, parent, true)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai attribute.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique la désignation brute d'un identifiant Kaitai. * +* * +* Retour : Valeur brute de l'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_raw_id(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + const char *value; /* Valeur à transmettre */ + +#define KAITAI_ATTRIBUTE_RAW_ID_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + raw_id, py_kaitai_attribute, \ + "Raw value used by Kaitai to identify one attribute" \ + " among others.\n" \ + "\n" \ + "The returned indentifier is a string value." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + value = g_kaitai_attribute_get_raw_id(attrib); + + if (value == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + result = PyUnicode_FromString(value); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique la désignation originelle d'un identifiant Kaitai. * +* * +* Retour : Valeur originelle de l'identifiant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_original_id(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + const char *value; /* Valeur à transmettre */ + +#define KAITAI_ATTRIBUTE_ORIGINAL_ID_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + original_id, py_kaitai_attribute, \ + "Optional alternative identifier for the attribute, as seen in" \ + " the original specifications.\n" \ + "\n" \ + "The returned value is a string or *None*." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + value = g_kaitai_attribute_get_original_id(attrib); + + if (value == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + result = PyUnicode_FromString(value); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit une éventuelle documentation concernant l'attribut. * +* * +* Retour : Description enregistrée ou None si absente. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_doc(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + const char *doc; /* Documentation à transmettre */ + +#define KAITAI_ATTRIBUTE_DOC_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + doc, py_kaitai_attribute, \ + "Optional documentation for the attribute.\n" \ + "\n" \ + "The returned value is a string or *None*." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + doc = g_kaitai_attribute_get_doc(attrib); + + if (doc == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + result = PyUnicode_FromString(doc); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Détermine si l'attribue porte une valeur entière signée. * +* * +* Retour : Bilan de la consultation : True si un entier signé est visé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_attribute_get_handle_signed_integer(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiAttribute *attrib; /* Version native de l'attribut*/ + bool status; /* Bilan d'une consultation */ + +#define KAITAI_ATTRIBUTE_HANDLE_SIGNED_INTEGER_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + handle_signed_integer, py_kaitai_attribute, \ + "Sign of the carried integer value, if any: positive or negative?\n" \ + "\n" \ + "This status is provided as a boolean value." \ +) + + attrib = G_KAITAI_ATTRIBUTE(pygobject_get(self)); + + status = g_kaitai_attribute_handle_signed_integer(attrib); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_attribute_type(void) +{ + static PyMethodDef py_kaitai_attribute_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_attribute_getseters[] = { + KAITAI_ATTRIBUTE_RAW_ID_ATTRIB, + KAITAI_ATTRIBUTE_ORIGINAL_ID_ATTRIB, + KAITAI_ATTRIBUTE_DOC_ATTRIB, + KAITAI_ATTRIBUTE_HANDLE_SIGNED_INTEGER_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_attribute_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiAttribute", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_ATTRIBUTE_DOC, + + .tp_methods = py_kaitai_attribute_methods, + .tp_getset = py_kaitai_attribute_getseters, + + .tp_init = py_kaitai_attribute_init, + .tp_new = py_kaitai_attribute_new, + + }; + + return &py_kaitai_attribute_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....KaitaiAttribute. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_attribute_is_registered(void) +{ + PyTypeObject *type; /* Type 'KaitaiAttribute' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_attribute_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_parser_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ATTRIBUTE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en attribut de données Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_attribute(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_attribute_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai attribute"); + break; + + case 1: + *((GKaitaiAttribute **)dst) = G_KAITAI_ATTRIBUTE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/attribute.h b/plugins/kaitai/python/parsers/attribute.h new file mode 100644 index 0000000..931e769 --- /dev/null +++ b/plugins/kaitai/python/parsers/attribute.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * attribute.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/attribute.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_attribute_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiAttribute'. */ +bool ensure_python_kaitai_attribute_is_registered(void); + +/* Tente de convertir en attribut de données Kaitai. */ +int convert_to_kaitai_attribute(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_ATTRIBUTE_H */ diff --git a/plugins/kaitai/python/parsers/enum.c b/plugins/kaitai/python/parsers/enum.c new file mode 100644 index 0000000..9200c6f --- /dev/null +++ b/plugins/kaitai/python/parsers/enum.c @@ -0,0 +1,468 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enum.h - équivalent Python du fichier "plugins/kaitai/parsers/enum.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "enum.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "../../parsers/enum-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_enum, G_TYPE_KAITAI_ENUM); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_enum_init(PyObject *, PyObject *, PyObject *); + +/* Traduit une étiquette brute en constante d'énumération. */ +static PyObject *py_kaitai_enum_find_value(PyObject *, PyObject *); + +/* Traduit une constante d'énumération en étiquette brute. */ +static PyObject *py_kaitai_enum_find_label(PyObject *, PyObject *); + +/* Traduit une constante d'énumération en documentation. */ +static PyObject *py_kaitai_enum_find_documentation(PyObject *, PyObject *); + +/* Fournit le nom principal d'une énumération. */ +static PyObject *py_kaitai_enum_get_name(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_enum_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Création GLib à transmettre */ + +#define KAITAI_ENUM_DOC \ + "The KaitaiEnum class maps integer constants to symbolic names using" \ + " Kaitai definitions.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiEnum(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the EnumSpec" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + if (!g_kaitai_enum_create(kenum, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai enumeration.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'énumération Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Traduit une étiquette brute en constante d'énumération. * +* * +* Retour : Valeur retrouvée ou None en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_find_value(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + const char *label; /* Etiquette à rechercher */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Enumération Kaitai courante */ + sized_string_t cstr; /* CHaîne avec sa longueur */ + bool status; /* Bilan de la conversion */ + resolved_value_t value; /* valeur à transformer */ + +#define KAITAI_ENUM_FIND_VALUE_METHOD PYTHON_METHOD_DEF \ +( \ + find_value, "$self, label", \ + METH_VARARGS, py_kaitai_enum, \ + "Translate a given enumeration label into its relative value.\n" \ + "\n" \ + "The *label* argument is expected to be a string.\n" \ + "\n" \ + "The result is an integer or *None* in case of resolution failure." \ +) + + ret = PyArg_ParseTuple(args, "s", &label); + if (!ret) return NULL; + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + cstr.data = (char *)label; + cstr.len = strlen(label); + + status = g_kaitai_enum_find_value(kenum, &cstr, &value); + + if (status) + { + if (value.type == GVT_UNSIGNED_INTEGER) + result = PyLong_FromUnsignedLongLong(value.unsigned_integer); + else + { + assert(value.type == GVT_SIGNED_INTEGER); + result = PyLong_FromLongLong(value.signed_integer); + } + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'énumération Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Traduit une constante d'énumération en étiquette brute. * +* * +* Retour : Désignation ou None en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_find_label(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + int prefix; /* Préfixe attendu ? */ + resolved_value_t value; /* valeur à transformer */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Enumération Kaitai courante */ + char *label; /* Etiquette reconstruite */ + +#define KAITAI_ENUM_FIND_LABEL_METHOD PYTHON_METHOD_DEF \ +( \ + find_label, "$self, value, / , prefix=False", \ + METH_VARARGS, py_kaitai_enum, \ + "Provide the label linked to a constant value within the current" \ + " enumeration.\n" \ + "\n" \ + "The *value* is a simple integer, and *prefix* is a boolean indicating" \ + " if the result has to integrate the enumeration name as a prefix.\n" \ + "\n" \ + "The result is a string or *None* in case of resolution failure." \ +) + + prefix = 0; + + ret = PyArg_ParseTuple(args, "K|p", &value.unsigned_integer, prefix); + if (!ret) return NULL; + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + value.type = GVT_UNSIGNED_INTEGER; + label = g_kaitai_enum_find_label(kenum, &value, prefix); + + if (label != NULL) + { + result = PyUnicode_FromString(label); + free(label); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'énumération Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Traduit une constante d'énumération en documentation. * +* * +* Retour : Documentation associée à la valeur indiquée ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_find_documentation(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + resolved_value_t value; /* valeur à transformer */ + int ret; /* Bilan de lecture des args. */ + GKaitaiEnum *kenum; /* Enumération Kaitai courante */ + char *doc; /* Documentation obtenue */ + +#define KAITAI_ENUM_FIND_DOCUMENTATION_METHOD PYTHON_METHOD_DEF \ +( \ + find_documentation, "$self, value", \ + METH_VARARGS, py_kaitai_enum, \ + "Provide the optional documentation linked to a constant value within" \ + " the current enumeration.\n" \ + "\n" \ + "The *value* is a simple integer.\n" \ + "\n" \ + "The result is a string or *None* if no documentation is registered" \ + " for the provided value." \ +) + + ret = PyArg_ParseTuple(args, "K", &value.unsigned_integer); + if (!ret) return NULL; + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + value.type = GVT_UNSIGNED_INTEGER; + doc = g_kaitai_enum_find_documentation(kenum, &value); + + if (doc != NULL) + { + result = PyUnicode_FromString(doc); + free(doc); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit le nom principal d'une énumération. * +* * +* Retour : Désignation de l'énumération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_enum_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiEnum *kenum; /* Version native de l'objet */ + const char *name; /* Valeur à transmettre */ + +#define KAITAI_ENUM_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_kaitai_enum, \ + "Name of the enumeration group, as a string value." \ +) + + kenum = G_KAITAI_ENUM(pygobject_get(self)); + + name = g_kaitai_enum_get_name(kenum); + + result = PyUnicode_FromString(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_enum_type(void) +{ + static PyMethodDef py_kaitai_enum_methods[] = { + KAITAI_ENUM_FIND_VALUE_METHOD, + KAITAI_ENUM_FIND_LABEL_METHOD, + KAITAI_ENUM_FIND_DOCUMENTATION_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_enum_getseters[] = { + KAITAI_ENUM_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_enum_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiEnum", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_ENUM_DOC, + + .tp_methods = py_kaitai_enum_methods, + .tp_getset = py_kaitai_enum_getseters, + + .tp_init = py_kaitai_enum_init, + .tp_new = py_kaitai_enum_new + + }; + + return &py_kaitai_enum_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiEnum. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_enum_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiEnum' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_enum_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_ENUM, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en ensemble d'énumérations Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_enum(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_enum_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai enumeration"); + break; + + case 1: + *((GKaitaiEnum **)dst) = G_KAITAI_ENUM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/enum.h b/plugins/kaitai/python/parsers/enum.h new file mode 100644 index 0000000..7172e69 --- /dev/null +++ b/plugins/kaitai/python/parsers/enum.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * enum.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/enum.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_enum_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiEnum'. */ +bool ensure_python_kaitai_enum_is_registered(void); + +/* Tente de convertir en ensemble d'énumérations Kaitai. */ +int convert_to_kaitai_enum(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_ENUM_H */ diff --git a/plugins/kaitai/python/parsers/instance.c b/plugins/kaitai/python/parsers/instance.c new file mode 100644 index 0000000..d55b58c --- /dev/null +++ b/plugins/kaitai/python/parsers/instance.c @@ -0,0 +1,280 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instance.h - équivalent Python du fichier "plugins/kaitai/parsers/instance.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "instance.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "attribute.h" +#include "../../parsers/instance-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_instance, G_TYPE_KAITAI_INSTANCE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_instance_init(PyObject *, PyObject *, PyObject *); + +/* Indique le nom attribué à une instance Kaitai. */ +static PyObject *py_kaitai_instance_get_name(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_instance_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiInstance *attrib; /* Création GLib à transmettre */ + +#define KAITAI_INSTANCE_DOC \ + "KaitaiInstance is the class providing support for Kaitai computed" \ + " values.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiInstance(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the Instance" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + attrib = G_KAITAI_INSTANCE(pygobject_get(self)); + + if (!g_kaitai_instance_create(attrib, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai instance.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le nom attribué à une instance Kaitai. * +* * +* Retour : Désignation pointant l'instance. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_instance_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiInstance *inst; /* Version native de l'instance*/ + const char *name; /* Désignation à transmettre */ + +#define KAITAI_INSTANCE_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_kaitai_instance, \ + "Name used by Kaitai to identify the instance" \ + " among others.\n" \ + "\n" \ + "The returned indentifier is a string value." \ +) + + inst = G_KAITAI_INSTANCE(pygobject_get(self)); + + name = g_kaitai_instance_get_name(inst); + assert(name != NULL); + + result = PyUnicode_FromString(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_instance_type(void) +{ + static PyMethodDef py_kaitai_instance_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_instance_getseters[] = { + KAITAI_INSTANCE_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_instance_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiInstance", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_INSTANCE_DOC, + + .tp_methods = py_kaitai_instance_methods, + .tp_getset = py_kaitai_instance_getseters, + + .tp_init = py_kaitai_instance_init, + .tp_new = py_kaitai_instance_new, + + }; + + return &py_kaitai_instance_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....KaitaiInstance. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_instance_is_registered(void) +{ + PyTypeObject *type; /* Type 'KaitaiInstance' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_instance_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_attribute_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_INSTANCE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en instance Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_instance(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_instance_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai instance"); + break; + + case 1: + *((GKaitaiInstance **)dst) = G_KAITAI_INSTANCE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/instance.h b/plugins/kaitai/python/parsers/instance.h new file mode 100644 index 0000000..8a0a6cf --- /dev/null +++ b/plugins/kaitai/python/parsers/instance.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * instance.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/instance.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_instance_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiInstance'. */ +bool ensure_python_kaitai_instance_is_registered(void); + +/* Tente de convertir en instance Kaitai. */ +int convert_to_kaitai_instance(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_INSTANCE_H */ diff --git a/plugins/kaitai/python/parsers/meta.c b/plugins/kaitai/python/parsers/meta.c new file mode 100644 index 0000000..0bd7bf9 --- /dev/null +++ b/plugins/kaitai/python/parsers/meta.c @@ -0,0 +1,414 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * meta.h - équivalent Python du fichier "plugins/kaitai/parsers/meta.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "meta.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/yaml/python/node.h> + + +#include "../../parsers/meta-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_meta, G_TYPE_KAITAI_META); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_meta_init(PyObject *, PyObject *, PyObject *); + +/* Fournit l'identifié associé à une définiton Kaitai. */ +static PyObject *py_kaitai_meta_get_id(PyObject *, void *); + +/* Fournit la désignation humaine d'une définiton Kaitai. */ +static PyObject *py_kaitai_meta_get_title(PyObject *, void *); + +/* Indique la liste des définitions à importer. */ +static PyObject *py_kaitai_meta_get_dependencies(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_meta_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiMeta *kmeta; /* Création GLib à transmettre */ + +#define KAITAI_META_DOC \ + "The KaitaiMeta class stores general information about a Kaitai definition,"\ + " such as required imports or the default endianness for reading values.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiMeta(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the MetaSpec" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + kmeta = G_KAITAI_META(pygobject_get(self)); + + if (!g_kaitai_meta_create(kmeta, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai global description.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit l'identifié associé à une définiton Kaitai. * +* * +* Retour : Identifiant de définition complète ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_meta_get_id(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiMeta *meta; /* Version native de l'objet */ + const char *id; /* Valeur à transmettre */ + +#define KAITAI_META_ID_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + id, py_kaitai_meta, \ + "Identifier for the Kaitai definition, as a string" \ + " value or *None* if any." \ +) + + meta = G_KAITAI_META(pygobject_get(self)); + + id = g_kaitai_meta_get_id(meta); + + if (id != NULL) + result = PyUnicode_FromString(id); + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation humaine d'une définiton Kaitai. * +* * +* Retour : Intitulé de définition ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_meta_get_title(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiMeta *meta; /* Version native de l'objet */ + const char *title; /* Valeur à transmettre */ + +#define KAITAI_META_TITLE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + title, py_kaitai_meta, \ + "Humain description for the Kaitai definition, as a" \ + " string value or *None* if any." \ +) + + meta = G_KAITAI_META(pygobject_get(self)); + + title = g_kaitai_meta_get_title(meta); + + if (title != NULL) + result = PyUnicode_FromString(title); + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation humaine d'une définiton Kaitai. * +* * +* Retour : Intitulé de définition ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_meta_get_endian(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiMeta *meta; /* Version native de l'objet */ + SourceEndian endian; /* Valeur à transmettre */ + +#define KAITAI_META_ENDIAN_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + endian, py_kaitai_meta, \ + "Default endianness for the Kaitai definition, as a" \ + " pychrysalide.analysis.BinContent.SourceEndian value." \ +) + + meta = G_KAITAI_META(pygobject_get(self)); + + endian = g_kaitai_meta_get_endian(meta); + + result = cast_with_constants_group_from_type(get_python_binary_content_type(), "SourceEndian", endian); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique la liste des définitions à importer. * +* * +* Retour : Liste de désignations de définitions, vide ou non. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_meta_get_dependencies(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiMeta *meta; /* Version native de l'objet */ + const char * const *dependencies; /* Liste d'imports requis */ + size_t count; /* Quantité de ces imports */ + size_t i; /* Boucle de parcours */ + +#define KAITAI_META_DEPENDENCIES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + dependencies, py_kaitai_meta, \ + "Tuple of all definitions to import for the current" \ + " definition.\n" \ + "\n" \ + "The result may be an empty string list." \ +) + + meta = G_KAITAI_META(pygobject_get(self)); + + dependencies = g_kaitai_meta_get_dependencies(meta, &count); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + PyTuple_SetItem(result, i, PyUnicode_FromString(dependencies[i])); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_meta_type(void) +{ + static PyMethodDef py_kaitai_meta_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_meta_getseters[] = { + KAITAI_META_ID_ATTRIB, + KAITAI_META_TITLE_ATTRIB, + KAITAI_META_ENDIAN_ATTRIB, + KAITAI_META_DEPENDENCIES_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_meta_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiMeta", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_META_DOC, + + .tp_methods = py_kaitai_meta_methods, + .tp_getset = py_kaitai_meta_getseters, + + .tp_init = py_kaitai_meta_init, + .tp_new = py_kaitai_meta_new + + }; + + return &py_kaitai_meta_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiMeta. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_meta_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiMeta' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_meta_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_META, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en description globale Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_meta(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_meta_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai global description"); + break; + + case 1: + *((GKaitaiMeta **)dst) = G_KAITAI_META(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/yaml/python/line.h b/plugins/kaitai/python/parsers/meta.h index 00dcbd9..383cad9 100644 --- a/plugins/yaml/python/line.h +++ b/plugins/kaitai/python/parsers/meta.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * line.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/line.h" + * meta.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/meta.h" * * Copyright (C) 2019 Cyrille Bagard * @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_YAML_PYTHON_LINE_H -#define _PLUGINS_YAML_PYTHON_LINE_H +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_META_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_META_H #include <Python.h> @@ -32,14 +32,14 @@ /* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_yaml_line_type(void); +PyTypeObject *get_python_kaitai_meta_type(void); -/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlLine'. */ -bool register_python_yaml_line(PyObject *); +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiMeta'. */ +bool ensure_python_kaitai_meta_is_registered(void); -/* Tente de convertir en ligne de données au format Yaml. */ -int convert_to_yaml_line(PyObject *, void *); +/* Tente de convertir en description globale Kaitai. */ +int convert_to_kaitai_meta(PyObject *, void *); -#endif /* _PLUGINS_YAML_PYTHON_LINE_H */ +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_META_H */ diff --git a/plugins/kaitai/python/parsers/module.c b/plugins/kaitai/python/parsers/module.c new file mode 100644 index 0000000..549f728 --- /dev/null +++ b/plugins/kaitai/python/parsers/module.c @@ -0,0 +1,124 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire parsers en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "attribute.h" +#include "enum.h" +#include "instance.h" +#include "meta.h" +#include "struct.h" +#include "type.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.kaitai.parsers' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_parsers_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_KAITAI_PARSERS_DOC \ + "This module provides implementation for several Kaitai" \ + " definitions parsers." + + static PyModuleDef py_chrysalide_kaitai_parsers_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.kaitai.parsers", + .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_PARSERS_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + module = build_python_module(super, &py_chrysalide_kaitai_parsers_module); + + result = (module != NULL); + + assert(result); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.kaitai.parsers'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_kaitai_parsers_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_kaitai_attribute_is_registered(); + if (result) result = ensure_python_kaitai_enum_is_registered(); + if (result) result = ensure_python_kaitai_instance_is_registered(); + if (result) result = ensure_python_kaitai_meta_is_registered(); + if (result) result = ensure_python_kaitai_structure_is_registered(); + if (result) result = ensure_python_kaitai_type_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/kaitai/python/parsers/module.h b/plugins/kaitai/python/parsers/module.h new file mode 100644 index 0000000..d0fdd66 --- /dev/null +++ b/plugins/kaitai/python/parsers/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire parsers en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.kaitai.parsers' au module Python. */ +bool add_kaitai_parsers_module(void); + +/* Intègre les objets du module 'plugins.kaitai.parsers'. */ +bool populate_kaitai_parsers_module(void); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_MODULE_H */ diff --git a/plugins/kaitai/python/parsers/struct.c b/plugins/kaitai/python/parsers/struct.c new file mode 100644 index 0000000..900cd1b --- /dev/null +++ b/plugins/kaitai/python/parsers/struct.c @@ -0,0 +1,376 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * struct.h - équivalent Python du fichier "plugins/kaitai/struct.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "struct.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> + + +#include "../parser.h" +#include "../../parsers/struct-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_structure, G_TYPE_KAITAI_STRUCT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_structure_init(PyObject *, PyObject *, PyObject *); + +/* Parcourt un contenu binaire selon une description Kaitai. */ +static PyObject *py_kaitai_structure_parse(PyObject *, PyObject *); + +/* Fournit la désignation humaine d'une définiton Kaitai. */ +static PyObject *py_kaitai_structure_get_meta(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_structure_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *text; /* Contenu de règles à traiter */ + const char *filename; /* Fichier de définitions */ + int ret; /* Bilan de lecture des args. */ + GKaitaiStruct *kstruct; /* Création GLib à transmettre */ + + static char *kwlist[] = { "text", "filename", NULL }; + +#define KAITAI_STRUCT_DOC \ + "KaitaiStruct is the class providing support for parsing binary contents" \ + " using a special declarative language." \ + "\n" \ + "Instances can be created using one of the following constructors:\n" \ + "\n" \ + " KaitaiStruct(text=str)" \ + "\n" \ + " KaitaiStruct(filename=str)" \ + "\n" \ + "Where *text* is a string containg a markup content to parse; the" \ + " *filename* argument is an alternative string for a path pointing to the" \ + " same kind of content. This path can be a real filename or a resource" \ + " URI." \ + "\n" \ + "It is the Python bindings for a C implementation of the specifications" \ + " described at http://kaitai.io/." + + /* Récupération des paramètres */ + + text = NULL; + filename = NULL; + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, &text, &filename); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + kstruct = G_KAITAI_STRUCT(pygobject_get(self)); + + if (text != NULL) + { + if (!g_kaitai_structure_create_from_text(kstruct, text)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai structure.")); + return -1; + } + + } + + else if (filename != NULL) + { + if (!g_kaitai_structure_create_from_file(kstruct, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai structure.")); + return -1; + } + + } + + else + { + PyErr_SetString(PyExc_ValueError, _("Unable to create empty Kaitai structure.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance de l'interpréteur Kaitai à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Parcourt un contenu binaire selon une description Kaitai. * +* * +* Retour : Arborescence d'éléments rencontrés selon les spécifications. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_structure_parse(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + GBinContent *content; /* Contenu binaire à traiter */ + int ret; /* Bilan de lecture des args. */ + GKaitaiStruct *kstruct; /* Interpréteur Kaitai courant */ + GMatchRecord *record; /* Ensemble de correspondances */ + +#define KAITAI_STRUCTURE_PARSE_METHOD PYTHON_METHOD_DEF \ +( \ + parse, "$self, content", \ + METH_VARARGS, py_kaitai_structure, \ + "Parse a binary content with the loaded specifications." \ + "\n" \ + "The content has to be a pychrysalide.analysis.BinContent instance.\n" \ + "\n" \ + "The result is *None* if the parsing failed, or a" \ + " pychrysalide.plugins.kaitai.MatchRecord object for each attribute" \ + " met." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_binary_content, &content); + if (!ret) return NULL; + + kstruct = G_KAITAI_STRUCT(pygobject_get(self)); + + record = g_kaitai_structure_parse(kstruct, content); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation humaine d'une définiton Kaitai. * +* * +* Retour : Intitulé de définition OU None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_structure_get_meta(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiStruct *kstruct; /* Version native de l'objet */ + GKaitaiMeta *meta; /* Informations à transmettre */ + +#define KAITAI_STRUCTURE_META_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + meta, py_kaitai_structure, \ + "Global description provided for the Kaitai definition, as a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiMeta instance." \ +) + + kstruct = G_KAITAI_STRUCT(pygobject_get(self)); + + meta = g_kaitai_structure_get_meta(kstruct); + + if (meta != NULL) + { + result = pygobject_new(G_OBJECT(meta)); + g_object_unref(G_OBJECT(meta)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_structure_type(void) +{ + static PyMethodDef py_kaitai_structure_methods[] = { + KAITAI_STRUCTURE_PARSE_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_structure_getseters[] = { + KAITAI_STRUCTURE_META_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_structure_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiStruct", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_STRUCT_DOC, + + .tp_methods = py_kaitai_structure_methods, + .tp_getset = py_kaitai_structure_getseters, + + .tp_init = py_kaitai_structure_init, + .tp_new = py_kaitai_structure_new + + }; + + return &py_kaitai_structure_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiStruct.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_structure_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiStruct' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_structure_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_parser_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_STRUCT, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en structure de données Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_structure(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_structure_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai structure"); + break; + + case 1: + *((GKaitaiStruct **)dst) = G_KAITAI_STRUCT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/struct.h b/plugins/kaitai/python/parsers/struct.h new file mode 100644 index 0000000..872f744 --- /dev/null +++ b/plugins/kaitai/python/parsers/struct.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * struct.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/struct.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_structure_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiStruct'. */ +bool ensure_python_kaitai_structure_is_registered(void); + +/* Tente de convertir en structure de données Kaitai. */ +int convert_to_kaitai_structure(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_STRUCT_H */ diff --git a/plugins/kaitai/python/parsers/type.c b/plugins/kaitai/python/parsers/type.c new file mode 100644 index 0000000..64a3419 --- /dev/null +++ b/plugins/kaitai/python/parsers/type.c @@ -0,0 +1,278 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.h - équivalent Python du fichier "plugins/kaitai/parsers/type.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "type.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/yaml/python/node.h> + + +#include "struct.h" +#include "../../parsers/type-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_type, G_TYPE_KAITAI_TYPE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_type_init(PyObject *, PyObject *, PyObject *); + +/* Indique le nom de scène du type représenté. */ +static PyObject *py_kaitai_type_get_name(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_type_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GYamlNode *parent; /* Noeud Yaml de l'attribut */ + int ret; /* Bilan de lecture des args. */ + GKaitaiType *attrib; /* Création GLib à transmettre */ + +#define KAITAI_TYPE_DOC \ + "The KaitaiType class provides support for user-defined type used in" \ + " Kaitai definitions.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiType(parent)" \ + "\n" \ + "Where *parent* is a pychrysalide.plugins.yaml.YamlNode instance pointing" \ + " to Yaml data to load.\n" \ + "\n" \ + "The class is the Python bindings for a C implementation of the TypesSpec" \ + " structure described at https://doc.kaitai.io/ksy_diagram.html." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_yaml_node, &parent); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + attrib = G_KAITAI_TYPE(pygobject_get(self)); + + if (!g_kaitai_type_create(attrib, parent)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai type.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le nom de scène du type représenté. * +* * +* Retour : Désignation humaine. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_type_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiType *type; /* Version native du type */ + const char *name; /* Désignation à transmettre */ + +#define KAITAI_TYPE_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_kaitai_type, \ + "Name of the user-defined type, provided as a unique" \ + " string value." \ +) + + type = G_KAITAI_TYPE(pygobject_get(self)); + + name = g_kaitai_type_get_name(type); + assert(name != NULL); + + result = PyUnicode_FromString(name); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_type_type(void) +{ + static PyMethodDef py_kaitai_type_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_type_getseters[] = { + KAITAI_TYPE_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_type_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.parsers.KaitaiType", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_TYPE_DOC, + + .tp_methods = py_kaitai_type_methods, + .tp_getset = py_kaitai_type_getseters, + + .tp_init = py_kaitai_type_init, + .tp_new = py_kaitai_type_new, + + }; + + return &py_kaitai_type_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....parsers.KaitaiType. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_type_is_registered(void) +{ + PyTypeObject *type; /* Type 'KaitaiType' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_type_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.parsers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_kaitai_structure_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_TYPE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en type particulier pour Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_type(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_type_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai type"); + break; + + case 1: + *((GKaitaiType **)dst) = G_KAITAI_TYPE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/parsers/type.h b/plugins/kaitai/python/parsers/type.h new file mode 100644 index 0000000..320bc71 --- /dev/null +++ b/plugins/kaitai/python/parsers/type.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * type.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/parsers/type.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H +#define _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_type_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.parsers.KaitaiType'. */ +bool ensure_python_kaitai_type_is_registered(void); + +/* Tente de convertir en type particulier pour Kaitai. */ +int convert_to_kaitai_type(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_PARSERS_TYPE_H */ diff --git a/plugins/yaml/python/line.c b/plugins/kaitai/python/record.c index 11898d2..4194a9a 100644 --- a/plugins/yaml/python/line.c +++ b/plugins/kaitai/python/record.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * line.c - équivalent Python du fichier "plugins/yaml/line.c" + * record.h - équivalent Python du fichier "plugins/kaitai/record.h" * * Copyright (C) 2019 Cyrille Bagard * @@ -22,126 +22,106 @@ */ -#include "line.h" +#include "record.h" #include <pygobject.h> +#include <plugins/pychrysalide/access.h> #include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/arch/vmpa.h> -#include "../line.h" +#include "parser.h" +#include "../record.h" -/* Crée un nouvel objet Python de type 'YamlLine'. */ -static PyObject *py_yaml_line_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_ABSTRACT_CONSTRUCTOR(match_record, G_TYPE_MATCH_RECORD, NULL); -/* Fournit la taille de l'indentation d'une ligne Yaml. */ -static PyObject *py_yaml_line_get_indent(PyObject *, void *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_match_record_init(PyObject *, PyObject *, PyObject *); -/* Indique si la ligne représente un élément de liste. */ -static PyObject *py_yaml_line_is_list_item(PyObject *, void *); +/* Modifie la référence au créateur de la correspondance. */ +static int py_match_record_set_creator(PyObject *, PyObject *, void *); -/* Fournit la charge utile associée à une ligne Yaml. */ -static PyObject *py_yaml_line_get_payload(PyObject *, void *); +/* Renvoie vers le lecteur à l'origine de la correspondance. */ +static PyObject *py_match_record_get_creator(PyObject *, void *); -/* Fournit la clef associée à une ligne Yaml si elle existe. */ -static PyObject *py_yaml_line_get_key(PyObject *, void *); +/* Fournit le contenu lié à une correspondance établie. */ +static PyObject *py_match_record_get_content(PyObject *, void *); -/* Fournit la valeur associée à une ligne Yaml si elle existe. */ -static PyObject *py_yaml_line_get_value(PyObject *, void *); +/* Calcule ou fournit la zone couverte par une correspondance. */ +static PyObject *py_match_record_get_range(PyObject *, void *); + +/* Lit les octets bruts couverts par une correspondance. */ +static PyObject *py_match_record_get_raw_bytes(PyObject *, void *); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'YamlLine'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_line_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_match_record_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - const char *raw; /* Données Yaml brutes */ - Py_ssize_t index; /* Indice de ligne associée */ int ret; /* Bilan de lecture des args. */ - GYamlLine *line; /* Création GLib à transmettre */ - -#define YAML_LINE_DOC \ - "YamlLine handles a line of Yaml data.\n" \ - "\n" \ - "The data may be a couple of key/value, a comment, aso.\n" \ - "\n" \ - "Instances can be created using the following constructor:\n" \ - "\n" \ - " YamlTree(raw, number)" \ - "\n" \ - "Where raw is a string providing raw data and number the index" \ - " of the line in the overall stream." - - ret = PyArg_ParseTuple(args, "sn", &raw, &index); - if (!ret) return NULL; - - line = g_yaml_line_new(raw, index); - - if (line == NULL) - { - result = Py_None; - Py_INCREF(result); - } - else - { - g_object_ref_sink(G_OBJECT(line)); - result = pygobject_new(G_OBJECT(line)); - g_object_unref(line); - } +#define MATCH_RECORD_DOC \ + "MatchRecord is an abstract class providing mainly location and raw" \ + " data of an area which has matched a part of a binary content." - return result; + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; } /****************************************************************************** * * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * +* Paramètres : self = correspondance à manipuler. * +* value = lecteur à l'origine de la correspondance. * +* closure = adresse non utilisée ici. * * * -* Description : Fournit la taille de l'indentation d'une ligne Yaml. * +* Description : Modifie la référence au créateur de la correspondance. * * * -* Retour : Taille de l'indentation rencontrée. * +* Retour : Bilan de la définition. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_line_get_indent(PyObject *self, void *closure) +static int py_match_record_set_creator(PyObject *self, PyObject *value, void *closure) { - PyObject *result; /* Résultat à retourner */ - GYamlLine *line; /* Version GLib du type */ - size_t indent; /* Taille de l'indentation */ - -#define YAML_LINE_INDENT_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - indent, py_yaml_line, \ - "Quantity of characters used for the indentation." \ -) + int result; /* Bilan à renvoyer */ + GMatchRecord *record; /* Version GLib de l'objet */ + GKaitaiParser *parser; /* Lecteur à l'origine */ - line = G_YAML_LINE(pygobject_get(self)); + record = G_MATCH_RECORD(pygobject_get(self)); - indent = g_yaml_line_count_indent(line); + if (!convert_to_kaitai_parser(value, &parser)) + result = -1; - result = PyLong_FromSize_t(indent); + else + { + g_match_record_fix_creator(record, parser); + result = 0; + } return result; @@ -150,35 +130,38 @@ static PyObject *py_yaml_line_get_indent(PyObject *self, void *closure) /****************************************************************************** * * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * +* Paramètres : self = correspondance à manipuler. * +* closure = adresse non utilisée ici. * * * -* Description : Indique si la ligne représente un élément de liste. * +* Description : Renvoie vers le lecteur à l'origine de la correspondance. * * * -* Retour : Statut de l'état lié à une liste d'éléments. * +* Retour : Lecteur à l'origine de la création. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_line_is_list_item(PyObject *self, void *closure) +static PyObject *py_match_record_get_creator(PyObject *self, void *closure) { - PyObject *result; /* Résultat à retourner */ - GYamlLine *line; /* Version GLib du type */ - bool status; /* Statut de la ligne */ - -#define YAML_LINE_IS_LIST_ITEM_ATTRIB PYTHON_IS_DEF_FULL \ -( \ - list_item, py_yaml_line, \ - "Tell if the line starts a new list item." \ + PyObject *result; /* Instance à retourner */ + GMatchRecord *record; /* Version GLib de l'objet */ + GKaitaiParser *parser; /* Lecteur à l'origine */ + +#define MATCH_RECORD_CREATOR_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + creator, py_match_record, \ + "Provide or define the pychrysalide.plugins.kaitai.KaitaiParser instance" \ + " which has created the record.\n" \ + "\n" \ + "This field should not be defined after the record creation in most cases." \ ) - line = G_YAML_LINE(pygobject_get(self)); + record = G_MATCH_RECORD(pygobject_get(self)); - status = g_yaml_line_is_list_item(line); + parser = g_match_record_get_creator(record); - result = status ? Py_True : Py_False; - Py_INCREF(result); + result = pygobject_new(G_OBJECT(parser)); + g_object_unref(parser); return result; @@ -190,31 +173,40 @@ static PyObject *py_yaml_line_is_list_item(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Fournit la charge utile associée à une ligne Yaml. * +* Description : Fournit le contenu lié à une correspondance établie. * * * -* Retour : Contenu sous forme de chaîne de caractères. * +* Retour : Contenu binaire associé. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_line_get_payload(PyObject *self, void *closure) +static PyObject *py_match_record_get_content(PyObject *self, void *closure) { - PyObject *result; /* Résultat à retourner */ - GYamlLine *line; /* Version GLib du type */ - const char *payload; /* Chaîne à transmettre */ - -#define YAML_LINE_PAYLOAD_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - payload, py_yaml_line, \ - "Payload of the Yaml line." \ -) + PyObject *result; /* Valeur à retourner */ + GMatchRecord *record; /* Conservation à consulter */ + GBinContent *content; /* Contenu associé */ - line = G_YAML_LINE(pygobject_get(self)); +#define MATCH_RECORD_CONTENT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + content, py_match_record, \ + "pychrysalide.analysis.BinContent instance linked to" \ + " the match record." \ +) - payload = g_yaml_line_get_payload(line); + record = G_MATCH_RECORD(pygobject_get(self)); + content = g_match_record_get_content(record); - result = PyUnicode_FromString(payload); + if (content != NULL) + { + result = pygobject_new(G_OBJECT(content)); + g_object_unref(G_OBJECT(content)); + } + else + { + result = Py_None; + Py_INCREF(result); + } return result; @@ -226,38 +218,33 @@ static PyObject *py_yaml_line_get_payload(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Fournit la clef associée à une ligne Yaml si elle existe. * +* Description : Calcule ou fournit la zone couverte par une correspondance. * * * -* Retour : Clef sous forme de chaîne de caractères ou None. * +* Retour : Zone de couverture déterminée. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_line_get_key(PyObject *self, void *closure) +static PyObject *py_match_record_get_range(PyObject *self, void *closure) { - PyObject *result; /* Résultat à retourner */ - GYamlLine *line; /* Version GLib du type */ - const char *key; /* Chaîne à transmettre */ - -#define YAML_LINE_KEY_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - key, py_yaml_line, \ - "Key linked to the Yaml line or None." \ -) - - line = G_YAML_LINE(pygobject_get(self)); + PyObject *result; /* Valeur à retourner */ + GMatchRecord *record; /* Conservation à consulter */ + mrange_t range; /* Couverture courante */ - key = g_yaml_line_get_key(line); +#define MATCH_RECORD_RANGE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + range, py_match_record, \ + "Area of the matched data for the parsed attribute" \ + " against a given binary content.\n" \ + "\n" \ + "This property is a pychrysalide.arch.mrange instance." \ +) - if (key == NULL) - { - result = Py_None; - Py_INCREF(result); - } + record = G_MATCH_RECORD(pygobject_get(self)); + g_match_record_get_range(record, &range); - else - result = PyUnicode_FromString(key); + result = build_from_internal_mrange(&range); return result; @@ -269,38 +256,33 @@ static PyObject *py_yaml_line_get_key(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Fournit la valeur associée à une ligne Yaml si elle existe. * +* Description : Lit les octets bruts couverts par une correspondance. * * * -* Retour : Valeur sous forme de chaîne de caractères ou None. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_line_get_value(PyObject *self, void *closure) +static PyObject *py_match_record_get_raw_bytes(PyObject *self, void *closure) { - PyObject *result; /* Résultat à retourner */ - GYamlLine *line; /* Version GLib du type */ - const char *value; /* Chaîne à transmettre */ - -#define YAML_LINE_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - value, py_yaml_line, \ - "Value linked to the Yaml line or None." \ -) + PyObject *result; /* Valeur à retourner */ + GMatchRecord *record; /* Conservation à consulter */ + bin_t *out; /* Données brutes à transmettre*/ + size_t len; /* Quantité de ces données */ - line = G_YAML_LINE(pygobject_get(self)); +#define MATCH_RECORD_RAW_BYTES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + raw_bytes, py_match_record, \ + "Raw bytes from the area covered by the record." \ +) - value = g_yaml_line_get_value(line); + record = G_MATCH_RECORD(pygobject_get(self)); - if (value == NULL) - { - result = Py_None; - Py_INCREF(result); - } + g_match_record_read_raw_bytes(record, &out, &len); - else - result = PyUnicode_FromString(value); + result = PyBytes_FromStringAndSize((char *)out, len); + free(out); return result; @@ -319,48 +301,49 @@ static PyObject *py_yaml_line_get_value(PyObject *self, void *closure) * * ******************************************************************************/ -PyTypeObject *get_python_yaml_line_type(void) +PyTypeObject *get_python_match_record_type(void) { - static PyMethodDef py_yaml_line_methods[] = { + static PyMethodDef py_match_record_methods[] = { { NULL } }; - static PyGetSetDef py_yaml_line_getseters[] = { - YAML_LINE_INDENT_ATTRIB, - YAML_LINE_IS_LIST_ITEM_ATTRIB, - YAML_LINE_PAYLOAD_ATTRIB, - YAML_LINE_KEY_ATTRIB, - YAML_LINE_VALUE_ATTRIB, + static PyGetSetDef py_match_record_getseters[] = { + MATCH_RECORD_CREATOR_ATTRIB, + MATCH_RECORD_CONTENT_ATTRIB, + MATCH_RECORD_RANGE_ATTRIB, + MATCH_RECORD_RAW_BYTES_ATTRIB, { NULL } }; - static PyTypeObject py_yaml_line_type = { + static PyTypeObject py_match_record_type = { PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.plugins.yaml.YamlLine", + .tp_name = "pychrysalide.plugins.kaitai.MatchRecord", .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = MATCH_RECORD_DOC, - .tp_doc = YAML_LINE_DOC, + .tp_methods = py_match_record_methods, + .tp_getset = py_match_record_getseters, - .tp_methods = py_yaml_line_methods, - .tp_getset = py_yaml_line_getseters, - .tp_new = py_yaml_line_new + .tp_init = py_match_record_init, + .tp_new = py_match_record_new, }; - return &py_yaml_line_type; + return &py_match_record_type; } /****************************************************************************** * * -* Paramètres : module = module dont la définition est à compléter. * +* Paramètres : - * * * -* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlLine. * +* Description : Prend en charge l'objet 'pychrysalide.plugins...MatchRecord. * * * * Retour : Bilan de l'opération. * * * @@ -368,17 +351,24 @@ PyTypeObject *get_python_yaml_line_type(void) * * ******************************************************************************/ -bool register_python_yaml_line(PyObject *module) +bool ensure_python_match_record_is_registered(void) { - PyTypeObject *type; /* Type Python 'YamlLine' */ + PyTypeObject *type; /* Type Python 'MatchRecord' */ + PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - type = get_python_yaml_line_type(); + type = get_python_match_record_type(); - dict = PyModule_GetDict(module); + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); - if (!register_class_for_pygobject(dict, G_TYPE_YAML_LINE, type, &PyGObject_Type)) - return false; + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_MATCH_RECORD, type)) + return false; + + } return true; @@ -390,7 +380,7 @@ bool register_python_yaml_line(PyObject *module) * Paramètres : arg = argument quelconque à tenter de convertir. * * dst = destination des valeurs récupérées en cas de succès. * * * -* Description : Tente de convertir en ligne de données au format Yaml. * +* Description : Tente de convertir en conservation de correspondance. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * @@ -398,11 +388,11 @@ bool register_python_yaml_line(PyObject *module) * * ******************************************************************************/ -int convert_to_yaml_line(PyObject *arg, void *dst) +int convert_to_match_record(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ - result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_line_type()); + result = PyObject_IsInstance(arg, (PyObject *)get_python_match_record_type()); switch (result) { @@ -412,11 +402,11 @@ int convert_to_yaml_line(PyObject *arg, void *dst) break; case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml line"); + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to match record"); break; case 1: - *((GYamlLine **)dst) = G_YAML_LINE(pygobject_get(arg)); + *((GMatchRecord **)dst) = G_MATCH_RECORD(pygobject_get(arg)); break; default: diff --git a/plugins/yaml/python/tree.h b/plugins/kaitai/python/record.h index df9d5b8..edf75fc 100644 --- a/plugins/yaml/python/tree.h +++ b/plugins/kaitai/python/record.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * tree.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/tree.h" + * record.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/record.h" * * Copyright (C) 2019 Cyrille Bagard * @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_YAML_PYTHON_TREE_H -#define _PLUGINS_YAML_PYTHON_TREE_H +#ifndef _PLUGINS_KAITAI_PYTHON_RECORD_H +#define _PLUGINS_KAITAI_PYTHON_RECORD_H #include <Python.h> @@ -32,14 +32,14 @@ /* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_yaml_tree_type(void); +PyTypeObject *get_python_match_record_type(void); -/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlTree'. */ -bool register_python_yaml_tree(PyObject *); +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.MatchRecord'. */ +bool ensure_python_match_record_is_registered(void); -/* Tente de convertir en arborescence de lignes au format Yaml. */ -int convert_to_yaml_tree(PyObject *, void *); +/* Tente de convertir en conservation de correspondance. */ +int convert_to_match_record(PyObject *, void *); -#endif /* _PLUGINS_YAML_PYTHON_TREE_H */ +#endif /* _PLUGINS_KAITAI_PYTHON_RECORD_H */ diff --git a/plugins/kaitai/python/records/Makefile.am b/plugins/kaitai/python/records/Makefile.am new file mode 100644 index 0000000..3a3c672 --- /dev/null +++ b/plugins/kaitai/python/records/Makefile.am @@ -0,0 +1,19 @@ + +noinst_LTLIBRARIES = libkaitaipythonrecords.la + +libkaitaipythonrecords_la_SOURCES = \ + bits.h bits.c \ + delayed.h delayed.c \ + empty.h empty.c \ + group.h group.c \ + item.h item.c \ + list.h list.c \ + module.h module.c + +libkaitaipythonrecords_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaipythonrecords_la_SOURCES:%c=) diff --git a/plugins/kaitai/python/records/bits.c b/plugins/kaitai/python/records/bits.c new file mode 100644 index 0000000..f94148b --- /dev/null +++ b/plugins/kaitai/python/records/bits.c @@ -0,0 +1,318 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.h - équivalent Python du fichier "plugins/kaitai/parsers/bits.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "bits.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> + + +#include "../record.h" +#include "../parsers/attribute.h" +#include "../../records/bits-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_bit_field, G_TYPE_RECORD_BIT_FIELD); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_bit_field_init(PyObject *, PyObject *, PyObject *); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +static PyObject *py_record_bit_field_get_value(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_bit_field_init(PyObject *self, PyObject *args, PyObject *kwds) +{ +#if 0 + GKaitaiAttribute *attrib; /* Attribut défini créateur */ + GBinContent *content; /* Contenu binaire analysé */ + mrange_t range; /* Espace couvert */ + SourceEndian endian; /* Boutisme à observer */ + int ret; /* Bilan de lecture des args. */ + GRecordBitField *field; /* Création GLib à transmettre */ +#endif + +#define RECORD_BIT_FIELD_DOC \ + "The RecordItem class remembers a match between a described attribute and" \ + " its concret value read from parsed binary data." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordItem(content, range, endian, attrib)" \ + "\n" \ + "Where the *attrib* arguments refers to a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance as the" \ + " creator of the newly created object, *content* points to a" \ + " pychrysalide.analysis.BinContent instance, *range* is a" \ + " pychrysalide.arch.mrange object, *endian* states with a" \ + " pychrysalide.analysis.BinContent.SourceEndian hint the endianness used" \ + " to read integer values." + + /* Récupération des paramètres */ + +#if 0 /* FIXME */ + + ret = PyArg_ParseTuple(args, "O&O&O&", + convert_to_kaitai_attribute, &attrib, + convert_to_binary_content, &content, + convert_any_to_mrange, &range, + convert_to_binary_content, &endian); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + field = G_RECORD_BIT_FIELD(pygobject_get(self)); + + if (!g_record_bit_field_create(field, attrib, content, &range, endian)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record bit field.")); + return -1; + } + + return 0; + +#endif + + PyErr_SetString(PyExc_ValueError, _("Unable to create record bit field at the moment.")); + return -1; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_bit_field_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GRecordBitField *field; /* Version native de l'élément */ + resolved_value_t resolved; /* Valeur sous forme générique */ + bool status; /* Bilan d'opération */ + +#define RECORD_BIT_FIELD_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_record_bit_field, \ + "Carried value (as integer), or None in case of error." \ +) + + result = NULL; + + field = G_RECORD_BIT_FIELD(pygobject_get(self)); + + status = g_record_bit_field_get_value(field, &resolved); + + if (status) + switch (resolved.type) + { + case GVT_UNSIGNED_INTEGER: + result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer); + break; + + default: + assert(false); + result = Py_None; + Py_INCREF(result); + break; + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_bit_field_type(void) +{ + static PyMethodDef py_record_bit_field_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_bit_field_getseters[] = { + RECORD_BIT_FIELD_VALUE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_record_bit_field_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordBitField", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_BIT_FIELD_DOC, + + .tp_methods = py_record_bit_field_methods, + .tp_getset = py_record_bit_field_getseters, + + .tp_init = py_record_bit_field_init, + .tp_new = py_record_bit_field_new, + + }; + + return &py_record_bit_field_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.....RecordBitField. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_bit_field_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordItem' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_bit_field_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_BIT_FIELD, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en correspondance attribut/binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_bit_field(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_bit_field_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record bit field"); + break; + + case 1: + *((GRecordBitField **)dst) = G_RECORD_BIT_FIELD(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/bits.h b/plugins/kaitai/python/records/bits.h new file mode 100644 index 0000000..6c833bb --- /dev/null +++ b/plugins/kaitai/python/records/bits.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/bits.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_BITS_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_BITS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_bit_field_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordBitField'. */ +bool ensure_python_record_bit_field_is_registered(void); + +/* Tente de convertir en correspondance attribut/binaire. */ +int convert_to_record_bit_field(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_BITS_H */ diff --git a/plugins/kaitai/python/records/delayed.c b/plugins/kaitai/python/records/delayed.c new file mode 100644 index 0000000..32e3db1 --- /dev/null +++ b/plugins/kaitai/python/records/delayed.c @@ -0,0 +1,341 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * delayed.c - équivalent Python du fichier "plugins/kaitai/parsers/delayed.c" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "delayed.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> + + +#include "../record.h" +#include "../scope.h" +#include "../parsers/instance.h" +#include "../../records/delayed-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_delayed, G_TYPE_RECORD_DELAYED); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_delayed_init(PyObject *, PyObject *, PyObject *); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +static PyObject *py_record_delayed_get_value(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_delayed_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiInstance *inst; /* Instance définie créatrice */ + kaitai_scope_t *locals; /* Environnement local */ + GBinContent *content; /* Contenu binaire analysé */ + int ret; /* Bilan de lecture des args. */ + GRecordDelayed *delayed; /* Création GLib à transmettre */ + +#define RECORD_DELAYED_DOC \ + "The RecordDelayed class stores a link to an instance used to compute a" \ + " given value." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordDelayed(inst, locals, content)" \ + "\n" \ + "Where the *inst* arguments refers to a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiInstance instance as the" \ + " creator of the newly created object, *locals* points to a" \ + " pychrysalide.plugins.kaitai.KaitaiScope structure used as current scope." \ + " The *content* argument is a pychrysalide.analysis.BinContent instance if" \ + " the delayed instance does not define a direct value." + + /* Récupération des paramètres */ + + content = NULL; + + ret = PyArg_ParseTuple(args, "O&O&|O&", + convert_to_kaitai_instance, &inst, + convert_to_kaitai_scope, &locals, + convert_to_binary_content_or_none, &content); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + delayed = G_RECORD_DELAYED(pygobject_get(self)); + + if (!g_record_delayed_create(delayed, inst, locals, content)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record delayed.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_delayed_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GRecordDelayed *delayed; /* Version native de l'élément */ + resolved_value_t resolved; /* Valeur sous forme générique */ + bool status; /* Bilan d'opération */ + +#define RECORD_DELAYED_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_record_delayed, \ + "Carried value (as integer, bytes), or None in case of error." \ +) + + result = NULL; + + delayed = G_RECORD_DELAYED(pygobject_get(self)); + + status = g_record_delayed_compute_and_aggregate_value(delayed, &resolved); + + if (status) + switch (resolved.type) + { + case GVT_ERROR: + assert(false); + PyErr_Format(PyExc_RuntimeError, + _("Error got while parsing Kaitai definition should not have been exported!")); + result = NULL; + break; + + case GVT_UNSIGNED_INTEGER: + result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer); + break; + + case GVT_SIGNED_INTEGER: + result = PyLong_FromLongLong(resolved.signed_integer); + break; + + case GVT_FLOAT: + result = PyFloat_FromDouble(resolved.floating_number); + break; + + case GVT_BOOLEAN: + result = resolved.status ? Py_True : Py_False; + Py_INCREF(result); + break; + + case GVT_BYTES: + result = PyBytes_FromStringAndSize(resolved.bytes.data, resolved.bytes.len); + exit_szstr(&resolved.bytes); + break; + + case GVT_ARRAY: + result = pygobject_new(G_OBJECT(resolved.array)); + break; + + case GVT_RECORD: + result = pygobject_new(G_OBJECT(resolved.record)); + break; + + case GVT_STREAM: + result = pygobject_new(G_OBJECT(resolved.stream)); + break; + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_delayed_type(void) +{ + static PyMethodDef py_record_delayed_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_delayed_getseters[] = { + RECORD_DELAYED_VALUE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_record_delayed_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordDelayed", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_DELAYED_DOC, + + .tp_methods = py_record_delayed_methods, + .tp_getset = py_record_delayed_getseters, + + .tp_init = py_record_delayed_init, + .tp_new = py_record_delayed_new, + + }; + + return &py_record_delayed_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide..records.RecordDelayed.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_delayed_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordDelayed' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_delayed_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_DELAYED, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en valeur calculée. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_delayed(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_delayed_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record delayed"); + break; + + case 1: + *((GRecordDelayed **)dst) = G_RECORD_DELAYED(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/delayed.h b/plugins/kaitai/python/records/delayed.h new file mode 100644 index 0000000..ba2d23a --- /dev/null +++ b/plugins/kaitai/python/records/delayed.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * delayed.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/delayed.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_DELAYED_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_DELAYED_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_delayed_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordDelayed'. */ +bool ensure_python_record_delayed_is_registered(void); + +/* Tente de convertir en valeur calculée. */ +int convert_to_record_delayed(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_DELAYED_H */ diff --git a/plugins/kaitai/python/records/empty.c b/plugins/kaitai/python/records/empty.c new file mode 100644 index 0000000..9861a39 --- /dev/null +++ b/plugins/kaitai/python/records/empty.c @@ -0,0 +1,286 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * empty.c - équivalent Python du fichier "plugins/kaitai/parsers/empty.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "empty.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> + + +#include "../parser.h" +#include "../record.h" +#include "../../records/empty-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_empty, G_TYPE_RECORD_EMPTY); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_empty_init(PyObject *, PyObject *, PyObject *); + +/* Produit une absence de valeur pour la correspondance. */ +static PyObject *py_record_empty_get_value(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_empty_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiParser *parser; /* Analyseur défini créateur */ + GBinContent *content; /* Contenu binaire manipulé */ + vmpa2t *pos; /* Tête de lecture courante */ + int ret; /* Bilan de lecture des args. */ + GRecordEmpty *empty; /* Création GLib à transmettre */ + +#define RECORD_EMPTY_DOC \ + "The RecordEmpty object reflects absolutely no match and should only get" \ + " in some rare cases.\n" \ + "\n" \ + "Instances can be created using following constructor:\n" \ + "\n" \ + " RecordEmpty(parser, content, pos)" \ + "\n" \ + "Where *parser* is the creator of the record, as a" \ + " pychrysalide.plugins.kaitai.KaitaiParser instance, *content* is a" \ + " pychrysalide.analysis.BinContent instance providing the processed data" \ + " and *pos* defines the current reading location, as a" \ + " pychrysalide.arch.vmpa value." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&O&", + convert_to_kaitai_parser, &parser, + convert_to_binary_content, &content, + convert_any_to_vmpa, &pos); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + empty = G_RECORD_EMPTY(pygobject_get(self)); + + if (!g_record_empty_create(empty, parser, content, pos)) + { + clean_vmpa_arg(pos); + + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream.")); + return -1; + + } + + clean_vmpa_arg(pos); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Produit une absence de valeur pour la correspondance. * +* * +* Retour : None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_empty_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + +#define RECORD_EMPTY_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_record_empty, \ + "Always *None*.\n" \ + "\n" \ + "This attribute is only provided to mimic other" \ + " record types." \ +) + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_empty_type(void) +{ + static PyMethodDef py_record_empty_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_empty_getseters[] = { + RECORD_EMPTY_VALUE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_record_empty_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordEmpty", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_EMPTY_DOC, + + .tp_methods = py_record_empty_methods, + .tp_getset = py_record_empty_getseters, + + .tp_init = py_record_empty_init, + .tp_new = py_record_empty_new, + + }; + + return &py_record_empty_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...records.RecordEmpty. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_empty_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordEmpty' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_empty_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_EMPTY, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en zone de correspondance vide. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_empty(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_empty_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record empty"); + break; + + case 1: + *((GRecordEmpty **)dst) = G_RECORD_EMPTY(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/empty.h b/plugins/kaitai/python/records/empty.h new file mode 100644 index 0000000..ecd5fc9 --- /dev/null +++ b/plugins/kaitai/python/records/empty.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * empty.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/empty.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_empty_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordEmpty'. */ +bool ensure_python_record_empty_is_registered(void); + +/* Tente de convertir en zone de correspondance vide. */ +int convert_to_record_empty(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_EMPTY_H */ diff --git a/plugins/kaitai/python/records/group.c b/plugins/kaitai/python/records/group.c new file mode 100644 index 0000000..a050043 --- /dev/null +++ b/plugins/kaitai/python/records/group.c @@ -0,0 +1,305 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * group.h - équivalent Python du fichier "plugins/kaitai/parsers/group.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "group.h" + + +#include <pygobject.h> +#include <string.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> + + +#include "../record.h" +#include "../parsers/struct.h" +#include "../../records/group-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_group, G_TYPE_RECORD_GROUP); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_group_init(PyObject *, PyObject *, PyObject *); + +/* Assure l'encadrement des accès aux champs d'une séquence. */ +static PyObject *py_record_group_getattr(PyObject *, char *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_group_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiStruct *kstruct; /* Séquence définie créatrice */ + GBinContent *content; /* Contenu binaire analysé */ + int ret; /* Bilan de lecture des args. */ + GRecordGroup *group; /* Création GLib à transmettre */ + +#define RECORD_GROUP_DOC \ + "The RecordGroup class stores a map of parsed attributes with their" \ + " relative values. Each of theses Kaitai attributes can be accessed as" \ + " usual Python attribute.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordGroup(kstruct, content)" \ + "\n" \ + "Where the *kstruct* refers to a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiStructure instance as the" \ + " creator of the newly created object, and *content* points to a" \ + " pychrysalide.analysis.BinContent instance." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&", + convert_to_kaitai_structure, &kstruct, + convert_to_binary_content, &content); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + group = G_RECORD_GROUP(pygobject_get(self)); + + if (!g_record_group_create(group, kstruct, content)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record group.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = structure C convertie en Python. * +* name = nom du champ auquel un accès est demandé. * +* * +* Description : Assure l'encadrement des accès aux champs d'une séquence. * +* * +* Retour : Valeur du champ demandé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_group_getattr(PyObject *self, char *name) +{ + PyObject *result; /* Elément à retourner */ + GRecordGroup *group; /* Version native de l'objet */ + GMatchRecord *found; /* Sous-élément identifié */ + PyObject *w; /* Conversion du nom de champ */ + PyTypeObject *tp; /* Type de l'objet manipulé */ + + group = G_RECORD_GROUP(pygobject_get(self)); + + found = g_match_record_find_by_name(G_MATCH_RECORD(group), name, strlen(name), DIRECT_SEARCH_DEEP_LEVEL); + + if (found != NULL) + { + result = pygobject_new(G_OBJECT(found)); + g_object_unref(G_OBJECT(found)); + } + + else + { + w = PyUnicode_InternFromString(name); + if (w == NULL) return NULL; + + tp = Py_TYPE(self); + + if (tp->tp_base->tp_getattro != NULL) + result = tp->tp_base->tp_getattro(self, w); + + else + { + PyErr_Format(PyExc_AttributeError, + "type object '%.50s' has no attribute '%U'", + tp->tp_name, name); + result = NULL; + } + + Py_DECREF(w); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_group_type(void) +{ + static PyMethodDef py_record_group_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_group_getseters[] = { + { NULL } + }; + + static PyTypeObject py_record_group_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordGroup", + .tp_basicsize = sizeof(PyGObject), + + .tp_getattr = py_record_group_getattr, + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_GROUP_DOC, + + .tp_methods = py_record_group_methods, + .tp_getset = py_record_group_getseters, + + .tp_init = py_record_group_init, + .tp_new = py_record_group_new, + + }; + + return &py_record_group_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...records.RecordGroup. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_group_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordGroup' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_group_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_GROUP, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en correspondances attribut/binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_group(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_group_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record group"); + break; + + case 1: + *((GRecordGroup **)dst) = G_RECORD_GROUP(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/group.h b/plugins/kaitai/python/records/group.h new file mode 100644 index 0000000..3e12ffc --- /dev/null +++ b/plugins/kaitai/python/records/group.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * group.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/group.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_group_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordGroup'. */ +bool ensure_python_record_group_is_registered(void); + +/* Tente de convertir en correspondances attribut/binaire. */ +int convert_to_record_group(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_GROUP_H */ diff --git a/plugins/kaitai/python/records/item.c b/plugins/kaitai/python/records/item.c new file mode 100644 index 0000000..84c2c58 --- /dev/null +++ b/plugins/kaitai/python/records/item.c @@ -0,0 +1,394 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - équivalent Python du fichier "plugins/kaitai/parsers/item.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "item.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> + + +#include "../record.h" +#include "../parsers/attribute.h" +#include "../../records/item-int.h" + + + +CREATE_DYN_CONSTRUCTOR(record_item, G_TYPE_RECORD_ITEM); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_item_init(PyObject *, PyObject *, PyObject *); + +/* Lit la série d'octets d'un élément Kaitai entier représenté. */ +static PyObject *py_record_item_get_truncated_bytes(PyObject *, void *); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +static PyObject *py_record_item_get_value(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_record_item_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiAttribute *attrib; /* Attribut défini créateur */ + GBinContent *content; /* Contenu binaire analysé */ + mrange_t range; /* Espace couvert */ + SourceEndian endian; /* Boutisme à observer */ + int ret; /* Bilan de lecture des args. */ + GRecordItem *item; /* Création GLib à transmettre */ + +#define RECORD_ITEM_DOC \ + "The RecordItem class remembers a match between a described attribute and" \ + " its concret value read from parsed binary data." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordItem(content, range, endian, attrib)" \ + "\n" \ + "Where the *attrib* arguments refers to a" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance as the" \ + " creator of the newly created object, *content* points to a" \ + " pychrysalide.analysis.BinContent instance, *range* is a" \ + " pychrysalide.arch.mrange object, *endian* states with a" \ + " pychrysalide.analysis.BinContent.SourceEndian hint the endianness used" \ + " to read integer values." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&O&", + convert_to_kaitai_attribute, &attrib, + convert_to_binary_content, &content, + convert_any_to_mrange, &range, + convert_to_binary_content, &endian); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + item = G_RECORD_ITEM(pygobject_get(self)); + + if (!g_record_item_create(item, attrib, content, &range, endian)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record item.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit la série d'octets d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_item_get_truncated_bytes(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GRecordItem *item; /* Version native de l'élément */ + bool status; /* Bilan d'opération */ + bin_t *out; /* Données brutes à transmettre*/ + size_t len; /* Quantité de ces données */ + +#define RECORD_ITEM_TRUNCATED_BYTES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + truncated_bytes, py_record_item, \ + "Raw bytes carried by the item (truncated if a separator" \ + " is defined in the linked attribute), or None if irrelevant" \ + " regarding to the type of the attribute." \ +) + + item = G_RECORD_ITEM(pygobject_get(self)); + + status = g_record_item_get_truncated_bytes(item, &out, &len); + + if (status) + { + result = PyBytes_FromStringAndSize((char *)out, len); + free(out); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_record_item_get_value(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GRecordItem *item; /* Version native de l'élément */ + resolved_value_t resolved; /* Valeur sous forme générique */ + bool status; /* Bilan d'opération */ + +#define RECORD_ITEM_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value, py_record_item, \ + "Carried value (as integer, bytes), or None in case of error." \ +) + + result = NULL; + + item = G_RECORD_ITEM(pygobject_get(self)); + + status = g_record_item_get_value(item, &resolved); + + if (status) + switch (resolved.type) + { + case GVT_ERROR: + assert(false); + PyErr_Format(PyExc_RuntimeError, + _("Error got while parsing Kaitai definition should not have been exported!")); + result = NULL; + break; + + case GVT_UNSIGNED_INTEGER: + result = PyLong_FromUnsignedLongLong(resolved.unsigned_integer); + break; + + case GVT_SIGNED_INTEGER: + result = PyLong_FromLongLong(resolved.signed_integer); + break; + + case GVT_FLOAT: + result = PyFloat_FromDouble(resolved.floating_number); + break; + + case GVT_BOOLEAN: + result = resolved.status ? Py_True : Py_False; + Py_INCREF(result); + break; + + case GVT_BYTES: + result = PyBytes_FromStringAndSize(resolved.bytes.data, resolved.bytes.len); + exit_szstr(&resolved.bytes); + break; + + case GVT_ARRAY: + result = pygobject_new(G_OBJECT(resolved.array)); + break; + + case GVT_RECORD: + result = pygobject_new(G_OBJECT(resolved.record)); + break; + + case GVT_STREAM: + result = pygobject_new(G_OBJECT(resolved.stream)); + break; + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_record_item_type(void) +{ + static PyMethodDef py_record_item_methods[] = { + { NULL } + }; + + static PyGetSetDef py_record_item_getseters[] = { + RECORD_ITEM_TRUNCATED_BYTES_ATTRIB, + RECORD_ITEM_VALUE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_record_item_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.records.RecordItem", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = RECORD_ITEM_DOC, + + .tp_methods = py_record_item_methods, + .tp_getset = py_record_item_getseters, + + .tp_init = py_record_item_init, + .tp_new = py_record_item_new, + + }; + + return &py_record_item_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....records.RecordItem. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_record_item_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordItem' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_record_item_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_match_record_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_ITEM, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en correspondance attribut/binaire. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_record_item(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_item_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record item"); + break; + + case 1: + *((GRecordItem **)dst) = G_RECORD_ITEM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/records/item.h b/plugins/kaitai/python/records/item.h new file mode 100644 index 0000000..bde8a55 --- /dev/null +++ b/plugins/kaitai/python/records/item.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/item.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_item_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordItem'. */ +bool ensure_python_record_item_is_registered(void); + +/* Tente de convertir en correspondance attribut/binaire. */ +int convert_to_record_item(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_ITEM_H */ diff --git a/plugins/yaml/python/scalar.c b/plugins/kaitai/python/records/list.c index 5a33cd1..d2eecbb 100644 --- a/plugins/yaml/python/scalar.c +++ b/plugins/kaitai/python/records/list.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * scalar.c - équivalent Python du fichier "plugins/yaml/scalar.c" + * list.h - équivalent Python du fichier "plugins/kaitai/parsers/list.h" * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019 Cyrille Bagard * * This file is part of Chrysalide. * @@ -22,71 +22,110 @@ */ -#include "scalar.h" +#include "list.h" #include <pygobject.h> +#include <string.h> +#include <i18n.h> +#include <plugins/pychrysalide/access.h> #include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> +#include <plugins/yaml/python/node.h> -#include "collection.h" -#include "line.h" -#include "node.h" -#include "../scalar.h" +#include "../record.h" +#include "../parsers/attribute.h" +#include "../../records/list-int.h" -/* Crée un nouvel objet Python de type 'YamlScalar'. */ -static PyObject *py_yaml_scalar_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(record_list, G_TYPE_RECORD_LIST); -/* Attache une collection de noeuds Yaml à un noeud. */ -static int py_yaml_scalar_set_collection(PyObject *, PyObject *, void *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_record_list_init(PyObject *, PyObject *, PyObject *); -/* Fournit une éventuelle collection rattachée à un noeud. */ -static PyObject *py_yaml_scalar_get_collection(PyObject *, void *); +/* Dénombre le nombre de correspondances enregistrées. */ +static Py_ssize_t py_record_list_sq_length(PyObject *); + +/* Fournit un élément ciblé dans la liste de correspondances. */ +static PyObject *py_record_list_sq_item(PyObject *, Py_ssize_t); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'YamlScalar'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_scalar_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_record_list_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - GYamlLine *key; /* Ligne principale du noeud */ + int result; /* Bilan à retourner */ + GKaitaiAttribute *attrib; /* Attribut défini créateur */ + GBinContent *content; /* Contenu binaire analysé */ + vmpa2t *addr; /* Adresse de symbole à ajouter*/ int ret; /* Bilan de lecture des args. */ - GYamlScalar *node; /* Création GLib à transmettre */ + GRecordList *list; /* Création GLib à transmettre */ + +#define RECORD_LIST_DOC \ + "The RecordList class collects a list of parsed attributes with their" \ + " relative values. Each of theses Kaitai attributes can be accessed as" \ + " subscriptable Python attribute.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " RecordList(content, attrib)" \ + "\n" \ + "Where the *attrib* argument refers to the" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiAttribute instance used to" \ + " create each record contained by the list and *content* points to a" \ + " pychrysalide.analysis.BinContent instance." + + result = 0; + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&", + convert_to_kaitai_attribute, &attrib, + convert_to_binary_content, &content, + convert_any_to_vmpa, &addr); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) + { + result = -1; + goto exit; + } -#define YAML_SCALAR_DOC \ - "YamlScalar handles a scalar node in a Yaml tree.\n" \ - "\n" \ - "Instances can be created using the following constructor:\n" \ - "\n" \ - " YamlScalar(key)\n" \ - "\n" \ - "Where key is the main Yaml line for the scalar." + /* Eléments de base */ - ret = PyArg_ParseTuple(args, "O&", &convert_to_yaml_line, &key); - if (!ret) return NULL; + list = G_RECORD_LIST(pygobject_get(self)); - node = g_yaml_scalar_new(key); + if (!g_record_list_create(list, attrib, content, addr)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create record list.")); + result = -1; + goto exit; + } - g_object_ref_sink(G_OBJECT(node)); - result = pygobject_new(G_OBJECT(node)); - g_object_unref(node); + exit: + + clean_vmpa_arg(addr); return result; @@ -95,44 +134,24 @@ static PyObject *py_yaml_scalar_new(PyTypeObject *type, PyObject *args, PyObject /****************************************************************************** * * -* Paramètres : self = contenu binaire à manipuler. * -* value = collection de noeuds Yaml. * -* closure = adresse non utilisée ici. * +* Paramètres : self = instance Python manipulée. * * * -* Description : Attache une collection de noeuds Yaml à un noeud. * +* Description : Dénombre le nombre de correspondances enregistrées. * * * -* Retour : Jeu d'attributs liés au contenu courant. * +* Retour : Taille de la liste représentée. * * * * Remarques : - * * * ******************************************************************************/ -static int py_yaml_scalar_set_collection(PyObject *self, PyObject *value, void *closure) +static Py_ssize_t py_record_list_sq_length(PyObject *self) { - int result; /* Bilan à renvoyer */ - GYamlScalar *node; /* Version GLib du noeud */ - GYamlCollection *collec; /* Version GLib de la valeur */ - - node = G_YAML_SCALAR(pygobject_get(self)); + Py_ssize_t result; /* Quantité à retourner */ + GRecordList *list; /* Version native de l'objet */ - if (value == Py_None) - { - g_yaml_scalar_set_collection(node, NULL); - result = 0; - } + list = G_RECORD_LIST(pygobject_get(self)); - else - { - if (!convert_to_yaml_collection(value, &collec)) - result = -1; - - else - { - g_yaml_scalar_set_collection(node, collec); - result = 0; - } - - } + result = g_record_list_count_records(list); return result; @@ -141,43 +160,36 @@ static int py_yaml_scalar_set_collection(PyObject *self, PyObject *value, void * /****************************************************************************** * * -* Paramètres : self = contenu binaire à manipuler. * -* closure = adresse non utilisée ici. * +* Paramètres : self = structure C convertie en Python. * +* index = indice de la correspondance visée. * * * -* Description : Fournit une éventuelle collection rattachée à un noeud. * +* Description : Fournit un élément ciblé dans la liste de correspondances. * * * -* Retour : Collection de noeuds Yaml ou None. * +* Retour : Instance de correspondance particulière, voire None. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_scalar_get_collection(PyObject *self, void *closure) +static PyObject *py_record_list_sq_item(PyObject *self, Py_ssize_t index) { PyObject *result; /* Instance à retourner */ - GYamlScalar *node; /* Version GLib du noeud */ - GYamlCollection *collec; /* Collection à transmettre */ - -#define YAML_SCALAR_COLLECTION_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - collection, py_yaml_scalar, \ - "Provide or define the collection of nodes attached to another Yaml node." \ -) + GRecordList *list; /* Version native de l'objet */ + GMatchRecord *record; /* Correspondance retrouvée */ - node = G_YAML_SCALAR(pygobject_get(self)); + list = G_RECORD_LIST(pygobject_get(self)); - collec = g_yaml_scalar_get_collection(node); + record = g_record_list_get_record(list, index); - if (collec == NULL) + if (record != NULL) { - result = Py_None; - Py_INCREF(result); + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); } - else { - result = pygobject_new(G_OBJECT(collec)); - g_object_unref(collec); + result = Py_None; + Py_INCREF(result); } return result; @@ -197,44 +209,54 @@ static PyObject *py_yaml_scalar_get_collection(PyObject *self, void *closure) * * ******************************************************************************/ -PyTypeObject *get_python_yaml_scalar_type(void) +PyTypeObject *get_python_record_list_type(void) { - static PyMethodDef py_yaml_scalar_methods[] = { + static PySequenceMethods py_record_list_sequence_methods = { + + .sq_length = py_record_list_sq_length, + .sq_item = py_record_list_sq_item, + + }; + + static PyMethodDef py_record_list_methods[] = { { NULL } }; - static PyGetSetDef py_yaml_scalar_getseters[] = { - YAML_SCALAR_COLLECTION_ATTRIB, + static PyGetSetDef py_record_list_getseters[] = { { NULL } }; - static PyTypeObject py_yaml_scalar_type = { + static PyTypeObject py_record_list_type = { PyVarObject_HEAD_INIT(NULL, 0) - .tp_name = "pychrysalide.plugins.yaml.YamlScalar", + .tp_name = "pychrysalide.plugins.kaitai.records.RecordList", .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_as_sequence = &py_record_list_sequence_methods, - .tp_doc = YAML_SCALAR_DOC, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - .tp_methods = py_yaml_scalar_methods, - .tp_getset = py_yaml_scalar_getseters, - .tp_new = py_yaml_scalar_new + .tp_doc = RECORD_LIST_DOC, + + .tp_methods = py_record_list_methods, + .tp_getset = py_record_list_getseters, + + .tp_init = py_record_list_init, + .tp_new = py_record_list_new, }; - return &py_yaml_scalar_type; + return &py_record_list_type; } /****************************************************************************** * * -* Paramètres : module = module dont la définition est à compléter. * +* Paramètres : - * * * -* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlScalar.* +* Description : Prend en charge l'objet 'pychrysalide....records.RecordList. * * * * Retour : Bilan de l'opération. * * * @@ -242,17 +264,27 @@ PyTypeObject *get_python_yaml_scalar_type(void) * * ******************************************************************************/ -bool register_python_yaml_scalar(PyObject *module) +bool ensure_python_record_list_is_registered(void) { - PyTypeObject *type; /* Type Python 'YamlScalar' */ + PyTypeObject *type; /* Type Python 'RecordList' */ + PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - type = get_python_yaml_scalar_type(); + type = get_python_record_list_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.records"); + + dict = PyModule_GetDict(module); - dict = PyModule_GetDict(module); + if (!ensure_python_match_record_is_registered()) + return false; - if (!register_class_for_pygobject(dict, G_TYPE_YAML_SCALAR, type, get_python_yaml_node_type())) - return false; + if (!register_class_for_pygobject(dict, G_TYPE_RECORD_LIST, type)) + return false; + + } return true; @@ -264,7 +296,7 @@ bool register_python_yaml_scalar(PyObject *module) * Paramètres : arg = argument quelconque à tenter de convertir. * * dst = destination des valeurs récupérées en cas de succès. * * * -* Description : Tente de convertir en noeud d'arborescence de format Yaml. * +* Description : Tente de convertir en correspondance attribut/binaire. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * @@ -272,11 +304,11 @@ bool register_python_yaml_scalar(PyObject *module) * * ******************************************************************************/ -int convert_to_yaml_scalar(PyObject *arg, void *dst) +int convert_to_record_list(PyObject *arg, void *dst) { int result; /* Bilan à retourner */ - result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_scalar_type()); + result = PyObject_IsInstance(arg, (PyObject *)get_python_record_list_type()); switch (result) { @@ -286,11 +318,11 @@ int convert_to_yaml_scalar(PyObject *arg, void *dst) break; case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml scalar"); + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to record list"); break; case 1: - *((GYamlScalar **)dst) = G_YAML_SCALAR(pygobject_get(arg)); + *((GRecordList **)dst) = G_RECORD_LIST(pygobject_get(arg)); break; default: diff --git a/plugins/kaitai/python/records/list.h b/plugins/kaitai/python/records/list.h new file mode 100644 index 0000000..53572a9 --- /dev/null +++ b/plugins/kaitai/python/records/list.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/records/list.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_record_list_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.records.RecordList'. */ +bool ensure_python_record_list_is_registered(void); + +/* Tente de convertir en correspondance attribut/binaire. */ +int convert_to_record_list(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_LIST_H */ diff --git a/plugins/kaitai/python/records/module.c b/plugins/kaitai/python/records/module.c new file mode 100644 index 0000000..af97434 --- /dev/null +++ b/plugins/kaitai/python/records/module.c @@ -0,0 +1,124 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire records en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "bits.h" +#include "delayed.h" +#include "empty.h" +#include "group.h" +#include "item.h" +#include "list.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.kaitai.records' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_records_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_KAITAI_RECORDS_DOC \ + "This module is providing objects used to link structure" \ + " definitions with their data." + + static PyModuleDef py_chrysalide_kaitai_records_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.kaitai.records", + .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_RECORDS_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + module = build_python_module(super, &py_chrysalide_kaitai_records_module); + + result = (module != NULL); + + assert(result); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.kaitai.records'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_kaitai_records_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_record_bit_field_is_registered(); + if (result) result = ensure_python_record_delayed_is_registered(); + if (result) result = ensure_python_record_empty_is_registered(); + if (result) result = ensure_python_record_group_is_registered(); + if (result) result = ensure_python_record_item_is_registered(); + if (result) result = ensure_python_record_list_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/kaitai/python/records/module.h b/plugins/kaitai/python/records/module.h new file mode 100644 index 0000000..ff631dc --- /dev/null +++ b/plugins/kaitai/python/records/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire records en tant que module + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H +#define _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.kaitai.records' au module Python. */ +bool add_kaitai_records_module(void); + +/* Intègre les objets du module 'plugins.kaitai.records'. */ +bool populate_kaitai_records_module(void); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_RECORDS_MODULE_H */ diff --git a/plugins/kaitai/python/rost/Makefile.am b/plugins/kaitai/python/rost/Makefile.am new file mode 100644 index 0000000..cae0419 --- /dev/null +++ b/plugins/kaitai/python/rost/Makefile.am @@ -0,0 +1,14 @@ + +noinst_LTLIBRARIES = libkaitaipythonrost.la + +libkaitaipythonrost_la_SOURCES = \ + module.h module.c \ + trigger.h trigger.c + +libkaitaipythonrost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitaipythonrost_la_SOURCES:%c=) diff --git a/plugins/kaitai/python/rost/module.c b/plugins/kaitai/python/rost/module.c new file mode 100644 index 0000000..66a5a82 --- /dev/null +++ b/plugins/kaitai/python/rost/module.c @@ -0,0 +1,115 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire rost en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <Python.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "trigger.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.kaitai.rost' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_rost_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_KAITAI_ROST_DOC \ + "This module creates some glue to extend the ROST features" \ + " using Kaitai definitions for analyzing and filtering" \ + " contents." + + static PyModuleDef py_chrysalide_kaitai_rost_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.kaitai.rost", + .m_doc = PYCHRYSALIDE_PLUGINS_KAITAI_ROST_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + module = build_python_module(super, &py_chrysalide_kaitai_rost_module); + + result = (module != NULL); + + assert(result); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.kaitai.rost'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_kaitai_rost_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_kaitai_trigger_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/kaitai/python/rost/module.h b/plugins/kaitai/python/rost/module.h new file mode 100644 index 0000000..8415c2e --- /dev/null +++ b/plugins/kaitai/python/rost/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire rost en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_ROST_MODULE_H +#define _PLUGINS_KAITAI_PYTHON_ROST_MODULE_H + + +#include <stdbool.h> + + + +/* Ajoute le module 'plugins.kaitai.rost' au module Python. */ +bool add_kaitai_rost_module(void); + +/* Intègre les objets du module 'plugins.kaitai.rost'. */ +bool populate_kaitai_rost_module(void); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_ROST_MODULE_H */ diff --git a/plugins/kaitai/python/rost/trigger.c b/plugins/kaitai/python/rost/trigger.c new file mode 100644 index 0000000..180ef6e --- /dev/null +++ b/plugins/kaitai/python/rost/trigger.c @@ -0,0 +1,236 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * trigger.c - équivalent Python du fichier "plugins/kaitai/rost/trigger.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "trigger.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/scan/item.h> + + +#include "../parsers/struct.h" +#include "../../parsers/struct.h" +#include "../../rost/trigger-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_trigger, G_TYPE_KAITAI_TRIGGER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_trigger_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_trigger_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GKaitaiStruct *kstruct; /* Définition Kaitai en place */ + int ret; /* Bilan de lecture des args. */ + GKaitaiTrigger *trigger; /* Création GLib à transmettre */ + +#define KAITAI_TRIGGER_DOC \ + "The KaitaiTrigger object store an access to a loaded Kaitai definition" \ + " creates as many as required instances from it when ROST filters contents" \ + " with the help of the Kaitai module.\n" \ + "\n" \ + "Instances can be created using following constructor:\n" \ + "\n" \ + " KaitaiTrigger(kstruct)" \ + "\n" \ + "Where *kstruct* is a pychrysalide.plugins.kaitai.parsers.KaitaiStruct" \ + " instance loaded with a valid Kaitai definition." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&", convert_to_kaitai_structure, &kstruct); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + trigger = G_KAITAI_TRIGGER(pygobject_get(self)); + + if (!g_kaitai_trigger_create(trigger, kstruct)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream.")); + return -1; + + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_trigger_type(void) +{ + static PyMethodDef py_kaitai_trigger_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_trigger_getseters[] = { + { NULL } + }; + + static PyTypeObject py_kaitai_trigger_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.rost.KaitaiTrigger", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_TRIGGER_DOC, + + .tp_methods = py_kaitai_trigger_methods, + .tp_getset = py_kaitai_trigger_getseters, + + .tp_init = py_kaitai_trigger_init, + .tp_new = py_kaitai_trigger_new, + + }; + + return &py_kaitai_trigger_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....rost.KaitaiTrigger. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_trigger_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'RecordEmpty' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_trigger_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai.rost"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_registered_item_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_TRIGGER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en accès à une définition Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_trigger(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_trigger_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai trigger"); + break; + + case 1: + *((GKaitaiTrigger **)dst) = G_KAITAI_TRIGGER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/rost/trigger.h b/plugins/kaitai/python/rost/trigger.h new file mode 100644 index 0000000..44776f7 --- /dev/null +++ b/plugins/kaitai/python/rost/trigger.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * trigger.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/rost/trigger.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_ROST_TRIGGER_H +#define _PLUGINS_KAITAI_PYTHON_ROST_TRIGGER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_trigger_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.rost.KaitaiTrigger'. */ +bool ensure_python_kaitai_trigger_is_registered(void); + +/* Tente de convertir en accès à une définition Kaitai. */ +int convert_to_kaitai_trigger(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_ROST_TRIGGER_H */ diff --git a/plugins/kaitai/python/scope.c b/plugins/kaitai/python/scope.c new file mode 100644 index 0000000..b11dc81 --- /dev/null +++ b/plugins/kaitai/python/scope.c @@ -0,0 +1,542 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope.c - équivalent Python du fichier "plugins/kaitai/scope.c" + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "scope.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "record.h" +#include "parsers/meta.h" +#include "../record.h" +#include "../parsers/meta.h" + + + +/* Rassemblement de données d'un paquet */ +typedef struct _py_kaitai_scope_t +{ + PyObject_HEAD /* A laisser en premier */ + + kaitai_scope_t *native; /* Tampon de données lié */ + +} py_kaitai_scope_t; + + +/* Libère de la mémoire un objet Python 'py_kaitai_scope_t'. */ +static void py_kaitai_scope_dealloc(py_kaitai_scope_t *); + +/* Initialise un objet Python de type 'py_kaitai_scope_t'. */ +static int py_kaitai_scope_init(py_kaitai_scope_t *, PyObject *, PyObject *); + +/* Conserve le souvenir de la dernière correspondance effectuée. */ +static PyObject *py_kaitai_scope_remember_last_record(PyObject *, PyObject *); + +/* Recherche la définition d'un type nouveau pour Kaitai. */ +static PyObject *py_kaitai_scope_find_sub_type(PyObject *, PyObject *); + +/* Retourne le souvenir d'une correspondance racine. */ +static PyObject *py_kaitai_scope_get_root_record(PyObject *, void *); + +/* Retourne le souvenir de la correspondance parente effectuée. */ +static PyObject *py_kaitai_scope_get_parent_record(PyObject *, void *); + +/* Retourne le souvenir de la dernière correspondance effectuée. */ +static PyObject *py_kaitai_scope_get_last_record(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à supprimer. * +* * +* Description : Libère de la mémoire un objet Python 'py_kaitai_scope_t'. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_kaitai_scope_dealloc(py_kaitai_scope_t *self) +{ + reset_record_scope(self->native); + + Py_TYPE(self)->tp_free((PyObject *)self); + +} + + +/****************************************************************************** +* * +* Paramètres : self = instance d'objet à initialiser. * +* args = arguments passés pour l'appel. * +* kwds = mots clefs éventuellement fournis en complément. * +* * +* Description : Initialise un objet Python de type 'py_kaitai_scope_t'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_scope_init(py_kaitai_scope_t *self, PyObject *args, PyObject *kwds) +{ + int result; /* Bilan à retourner */ + GKaitaiMeta *meta; /* Informations globale */ + int ret; /* Bilan de lecture des args. */ + +#define KAITAI_SCOPE_DOC \ + "The KaitaiScope object stores a local environment which freezes" \ + " a particular state of the Kaitai parser. It allows the dynamic" \ + " resolving of values contained in a Kaitai expression.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KaitaiScope(meta)" \ + "\n" \ + "Where *meta* is a pychrysalide.plugins.kaitai.parsers.KaitaiMeta" \ + " instance pointing to global information about the Kaitai" \ + " definition." + + ret = PyArg_ParseTuple(args, "O&", convert_to_kaitai_meta, &meta); + if (!ret) return -1; + + self->native = malloc(sizeof(kaitai_scope_t)); + + init_record_scope(self->native, meta); + + result = 0; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à manipuler. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Conserve le souvenir de la dernière correspondance effectuée.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_remember_last_record(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + GMatchRecord *record; /* Correspondance à utiliser */ + int ret; /* Bilan de lecture des args. */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + +#define KAITAI_SCOPE_REMEMBER_LAST_RECORD_METHOD PYTHON_METHOD_DEF \ +( \ + remember_last_record, "$self, record, /", \ + METH_VARARGS, py_kaitai_scope, \ + "Store a record as the last parsed record.\n" \ + "\n" \ + "This *record* is expected to be a" \ + " pychrysalide.plugins.kaitai.MatchRecord instance." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_match_record, &record); + if (!ret) return NULL; + + locals = (py_kaitai_scope_t *)self; + + remember_last_record(locals->native, record); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à manipuler. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Recherche la définition d'un type nouveau pour Kaitai. * +* * +* Retour : Type prêt à emploi ou NULL si non trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_find_sub_type(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + const char *name; /* Désignation à retrouver */ + int ret; /* Bilan de lecture des args. */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GKaitaiType *type; /* Définition à identifier */ + +#define KAITAI_SCOPE_FIND_SUB_TYPE_METHOD PYTHON_METHOD_DEF \ +( \ + find_sub_type, "$self, name, /", \ + METH_VARARGS, py_kaitai_scope, \ + "Retrieve the type structure linked to a given name.\n" \ + "\n" \ + "This *name* has to be a string.\n" \ + "\n" \ + "The result is a known" \ + " pychrysalide.plugins.kaitai.parsers.KaitaiType instance" \ + " or *None* if the name has not been registered during" \ + " the parsing." \ +) + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return NULL; + + locals = (py_kaitai_scope_t *)self; + + type = find_sub_type(locals->native, name); + + result = pygobject_new(G_OBJECT(type)); + g_object_unref(G_OBJECT(type)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à consulter. * +* closure = adresse non utilisée ici. * +* * +* Description : Retourne le souvenir d'une correspondance racine. * +* * +* Retour : Dernière correspondance établie ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_get_root_record(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GMatchRecord *record; /* Correspondance à convertir */ + +#define KAITAI_SCOPE_ROOT_RECORD_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + root_record, py_kaitai_scope, \ + "Provide the first record for a parsed content.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.kaitai.MatchRecord" \ + " instance or *None*." \ +) + + locals = (py_kaitai_scope_t *)self; + + record = get_root_record(locals->native); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à consulter. * +* closure = adresse non utilisée ici. * +* * +* Description : Retourne le souvenir de la correspondance parente effectuée. * +* * +* Retour : Dernière correspondance établie ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_get_parent_record(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GMatchRecord *record; /* Correspondance à convertir */ + +#define KAITAI_SCOPE_PARENT_RECORD_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + parent_record, py_kaitai_scope, \ + "Provide the current parent record for a parsed content.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.kaitai.MatchRecord" \ + " instance or *None*." \ +) + + locals = (py_kaitai_scope_t *)self; + + record = get_parent_record(locals->native); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = environnement local à consulter. * +* closure = adresse non utilisée ici. * +* * +* Description : Retourne le souvenir de la dernière correspondance effectuée.* +* * +* Retour : Dernière correspondance établie ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_scope_get_last_record(PyObject *self, void *closure) +{ + PyObject *result; /* Conversion à retourner */ + py_kaitai_scope_t *locals; /* Instance à manipuler */ + GMatchRecord *record; /* Correspondance à convertir */ + +#define KAITAI_SCOPE_LAST_RECORD_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + last_record, py_kaitai_scope, \ + "Provide the last createdrecord for a parsed content.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.kaitai.MatchRecord" \ + " instance or *None*." \ +) + + locals = (py_kaitai_scope_t *)self; + + record = get_last_record(locals->native); + + if (record != NULL) + { + result = pygobject_new(G_OBJECT(record)); + g_object_unref(G_OBJECT(record)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_scope_type(void) +{ + static PyMethodDef py_kaitai_scope_methods[] = { + KAITAI_SCOPE_REMEMBER_LAST_RECORD_METHOD, + KAITAI_SCOPE_FIND_SUB_TYPE_METHOD, + { NULL } + }; + + static PyGetSetDef py_kaitai_scope_getseters[] = { + KAITAI_SCOPE_ROOT_RECORD_ATTRIB, + KAITAI_SCOPE_PARENT_RECORD_ATTRIB, + KAITAI_SCOPE_LAST_RECORD_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_scope_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiScope", + .tp_basicsize = sizeof(py_kaitai_scope_t), + + .tp_dealloc = (destructor)py_kaitai_scope_dealloc, + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = KAITAI_SCOPE_DOC, + + .tp_methods = py_kaitai_scope_methods, + .tp_getset = py_kaitai_scope_getseters, + + .tp_init = (initproc)py_kaitai_scope_init, + .tp_new = PyType_GenericNew, + + }; + + return &py_kaitai_scope_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_scope_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PackedBuffer' */ + PyObject *module; /* Module à recompléter */ + + type = get_python_kaitai_scope_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + if (PyType_Ready(type) != 0) + return false; + + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + if (!register_python_module_object(module, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = structure interne à copier en objet Python. * +* * +* Description : Convertit une structure 'kaitai_scope_t' en objet Python. * +* * +* Retour : Object Python résultant de la conversion opérée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *build_from_internal_kaitai_scope(const kaitai_scope_t *locals) +{ + PyObject *result; /* Instance à retourner */ + PyTypeObject *type; /* Type à instancier */ + + type = get_python_kaitai_scope_type(); + + result = PyObject_CallObject((PyObject *)type, NULL); + + copy_record_scope(((py_kaitai_scope_t *)result)->native, locals); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en environnement local pour Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_scope(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_scope_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai scope"); + break; + + case 1: + *((kaitai_scope_t **)dst) = ((py_kaitai_scope_t *)arg)->native; + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/scope.h b/plugins/kaitai/python/scope.h new file mode 100644 index 0000000..9353b06 --- /dev/null +++ b/plugins/kaitai/python/scope.h @@ -0,0 +1,51 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/scope.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_SCOPE_H +#define _PLUGINS_KAITAI_PYTHON_SCOPE_H + + +#include <Python.h> +#include <stdbool.h> + + +#include "../scope.h" + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_scope_type(void); + +/* Prend en charge l'objet 'pychrysalide.common.PackedBuffer'. */ +bool ensure_python_kaitai_scope_is_registered(void); + +/* Convertit une structure 'kaitai_scope_t' en objet Python. */ +PyObject *build_from_internal_kaitai_scope(const kaitai_scope_t *); + +/* Tente de convertir en environnement local pour Kaitai. */ +int convert_to_kaitai_scope(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_SCOPE_H */ diff --git a/plugins/kaitai/python/stream.c b/plugins/kaitai/python/stream.c new file mode 100644 index 0000000..985e3c3 --- /dev/null +++ b/plugins/kaitai/python/stream.c @@ -0,0 +1,278 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * stream.h - équivalent Python du fichier "plugins/kaitai/stream.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "stream.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/arch/vmpa.h> + + +#include "../stream-int.h" + + + +CREATE_DYN_CONSTRUCTOR(kaitai_stream, G_TYPE_KAITAI_STREAM); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_kaitai_stream_init(PyObject *, PyObject *, PyObject *); + +/* Détermine si la fin des données a été atteinte. */ +static PyObject *py_kaitai_stream_get_eof(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_kaitai_stream_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + GBinContent *content; /* Contenu binaire manipulé */ + vmpa2t *pos; /* Tête de lecture courante */ + int ret; /* Bilan de lecture des args. */ + GKaitaiStream *stream; /* Création GLib à transmettre */ + +#define KAITAI_STREAM_DOC \ + "KaitaiStream collects all the information useful for the processing of" \ + " binary data." \ + "\n" \ + "Instances can be created using following constructor:\n" \ + "\n" \ + " KaitaiStream(content, pos)" \ + "\n" \ + "Where *content* is a pychrysalide.analysis.BinContent instance providing" \ + " the processed data and *pos* defines the current reading location, as a" \ + " pychrysalide.arch.vmpa value." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &content, convert_any_to_vmpa, &pos); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + stream = G_KAITAI_STREAM(pygobject_get(self)); + + if (!g_kaitai_stream_create(stream, content, pos)) + { + clean_vmpa_arg(pos); + + PyErr_SetString(PyExc_ValueError, _("Unable to create Kaitai stream.")); + return -1; + + } + + clean_vmpa_arg(pos); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Détermine si la fin des données a été atteinte. * +* * +* Retour : True si la tête de lecture est en position finale, ou False. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_kaitai_stream_get_eof(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GKaitaiStream *stream; /* Version native dyu flux */ + bool status; /* Etat de la position courante*/ + +#define KAITAI_STREAM_EOF_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + eof, py_kaitai_stream, \ + "Boolean value stating if the end of the stream" \ + " has been reached or not." \ +) + + stream = G_KAITAI_STREAM(pygobject_get(self)); + + status = g_kaitai_stream_has_reached_eof(stream); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_kaitai_stream_type(void) +{ + static PyMethodDef py_kaitai_stream_methods[] = { + { NULL } + }; + + static PyGetSetDef py_kaitai_stream_getseters[] = { + KAITAI_STREAM_EOF_ATTRIB, + { NULL } + }; + + static PyTypeObject py_kaitai_stream_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.kaitai.KaitaiStream", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KAITAI_STREAM_DOC, + + .tp_methods = py_kaitai_stream_methods, + .tp_getset = py_kaitai_stream_getseters, + + .tp_init = py_kaitai_stream_init, + .tp_new = py_kaitai_stream_new, + + }; + + return &py_kaitai_stream_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins...KaitaiStream.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_kaitai_stream_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'KaitaiStream' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_kaitai_stream_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.kaitai"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_KAITAI_STREAM, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en flux de données pour Kaitai. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_kaitai_stream(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_kaitai_stream_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Kaitai stream"); + break; + + case 1: + *((GKaitaiStream **)dst) = G_KAITAI_STREAM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/kaitai/python/stream.h b/plugins/kaitai/python/stream.h new file mode 100644 index 0000000..4f61358 --- /dev/null +++ b/plugins/kaitai/python/stream.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * stream.h - prototypes pour l'équivalent Python du fichier "plugins/kaitai/stream.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_KAITAI_PYTHON_STREAM_H +#define _PLUGINS_KAITAI_PYTHON_STREAM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_kaitai_stream_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.kaitai.KaitaiStream'. */ +bool ensure_python_kaitai_stream_is_registered(void); + +/* Tente de convertir en flux de données pour Kaitai. */ +int convert_to_kaitai_stream(PyObject *, void *); + + + +#endif /* _PLUGINS_KAITAI_PYTHON_STREAM_H */ diff --git a/plugins/kaitai/record-int.h b/plugins/kaitai/record-int.h new file mode 100644 index 0000000..5ce5b2c --- /dev/null +++ b/plugins/kaitai/record-int.h @@ -0,0 +1,73 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * record-int.h - prototypes internes pour la mémorisation d'une correspondance avec un attribut Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_RECORD_INT_H +#define PLUGINS_KAITAI_RECORD_INT_H + + +#include "record.h" + + +#include "parser.h" + + + +/* Calcule ou fournit la zone couverte par une correspondance. */ +typedef void (* get_record_range_fc) (const GMatchRecord *, mrange_t *); + +/* Recherche la correspondance associée à un identifiant. */ +typedef GMatchRecord * (* find_record_by_name_fc) (GMatchRecord *, const char *, size_t, unsigned int); + +/* Transforme une énumération en constante entière. */ +typedef bool (* resolve_record_enum_fc) (const GMatchRecord *, const sized_string_t *, const sized_string_t *, resolved_value_t *); + + +/* Correspondance entre un attribut et du binaire (instance) */ +struct _GMatchRecord +{ + GObject parent; /* A laisser en premier */ + + GKaitaiParser *creator; /* Lecteur à l'origine */ + + GBinContent *content; /* Contenu binaire analysé */ + +}; + +/* Correspondance entre un attribut et du binaire (classe) */ +struct _GMatchRecordClass +{ + GObjectClass parent; /* A laisser en premier */ + + get_record_range_fc get_range; /* Fourniture de couverture */ + find_record_by_name_fc find; /* Recherche selon identifiant */ + resolve_record_enum_fc resolve; /* Conversion d'une énumération*/ + +}; + + +/* Met en place une correspondance entre attribut et binaire. */ +bool g_match_record_create(GMatchRecord *, GKaitaiParser *, GBinContent *); + + + +#endif /* PLUGINS_KAITAI_RECORD_INT_H */ diff --git a/plugins/kaitai/record.c b/plugins/kaitai/record.c new file mode 100644 index 0000000..de1e80d --- /dev/null +++ b/plugins/kaitai/record.c @@ -0,0 +1,416 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * record.c - définition d'une correspondance avec un attribut Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "record.h" + + +#include <assert.h> + + +#include "expression.h" +#include "record-int.h" +#include "parsers/attribute.h" + + + +/* Initialise la classe des correspondances avec du binaire. */ +static void g_match_record_class_init(GMatchRecordClass *); + +/* Initialise une correspondance avec du binaire. */ +static void g_match_record_init(GMatchRecord *); + +/* Supprime toutes les références externes. */ +static void g_match_record_dispose(GMatchRecord *); + +/* Procède à la libération totale de la mémoire. */ +static void g_match_record_finalize(GMatchRecord *); + +/* Recherche la correspondance associée à un identifiant. */ +static GMatchRecord *_g_match_record_find_by_name(GMatchRecord *, const char *, size_t, unsigned int); + + + +/* Indique le type défini pour une correspondance avec du binaire. */ +G_DEFINE_TYPE(GMatchRecord, g_match_record, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des correspondances avec du binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_record_class_init(GMatchRecordClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_match_record_dispose; + object->finalize = (GObjectFinalizeFunc)g_match_record_finalize; + + klass->find = (find_record_by_name_fc)_g_match_record_find_by_name; + +} + + +/****************************************************************************** +* * +* Paramètres : record = instance à initialiser. * +* * +* Description : Initialise une correspondance avec du binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_record_init(GMatchRecord *record) +{ + record->creator = NULL; + + record->content = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : record = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_record_dispose(GMatchRecord *record) +{ + g_clear_object(&record->creator); + + g_clear_object(&record->content); + + G_OBJECT_CLASS(g_match_record_parent_class)->dispose(G_OBJECT(record)); + +} + + +/****************************************************************************** +* * +* Paramètres : record = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_match_record_finalize(GMatchRecord *record) +{ + G_OBJECT_CLASS(g_match_record_parent_class)->finalize(G_OBJECT(record)); + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à initialiser pleinement. * +* creator = lecteur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* * +* Description : Met en place une correspondance entre attribut et binaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_match_record_create(GMatchRecord *record, GKaitaiParser *creator, GBinContent *content) +{ + bool result; /* Bilan à retourner */ + + result = true; + + record->creator = creator; + g_object_ref(G_OBJECT(creator)); + + record->content = content; + + if (content != NULL) + g_object_ref(G_OBJECT(content)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à consulter. * +* * +* Description : Renvoie vers le lecteur à l'origine de la correspondance. * +* * +* Retour : Lecteur à l'origine de la création. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiParser *g_match_record_get_creator(const GMatchRecord *record) +{ + GKaitaiParser *result; /* Instance à retourner */ + + result = record->creator; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à modifier. * +* creator = lecteur à l'origine de la correspondance. * +* * +* Description : Modifie la référence au créateur de la correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_match_record_fix_creator(GMatchRecord *record, GKaitaiParser *creator) +{ + g_object_unref(G_OBJECT(record->creator)); + + record->creator = creator; + g_object_ref(G_OBJECT(creator)); + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à consulter. * +* * +* Description : Fournit le contenu lié à une correspondance établie. * +* * +* Retour : Contenu binaire associé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinContent *g_match_record_get_content(const GMatchRecord *record) +{ + GBinContent *result; /* Instance à retourner */ + + result = record->content; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à consulter. * +* range = zone de couverture déterminée. [OUT] * +* * +* Description : Calcule ou fournit la zone couverte par une correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_match_record_get_range(const GMatchRecord *record, mrange_t *range) +{ + GMatchRecordClass *class; /* Classe de l'instance */ + + class = G_MATCH_RECORD_GET_CLASS(record); + + class->get_range(record, range); + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance établie à consulter. * +* out = tableau d'octets retournés. [OUT] * +* len = taille de ce tableau alloué. [OUT] * +* * +* Description : Lit les octets bruts couverts par une correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_match_record_read_raw_bytes(const GMatchRecord *record, bin_t **out, size_t *len) +{ + mrange_t range; /* Zone de correspondance */ + const bin_t *data; /* Accès aux données brutes */ + + g_match_record_get_range(record, &range); + + *len = get_mrange_length(&range); + + data = g_binary_content_get_raw_access(record->content, get_mrange_addr(&range), *len); + assert(data != NULL); + + *out = malloc(sizeof(bin_t) * (*len + 1)); + + memcpy(*out, data, *len); + (*out)[*len] = '\0'; + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à consulter. * +* name = désignation de l'élément recherché. * +* len = taille de cette désignation. * +* level = profondeur maximale à atteindre (fond : 0). * +* * +* Description : Recherche la correspondance associée à un identifiant. * +* * +* Retour : Correspondance trouvée ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GMatchRecord *_g_match_record_find_by_name(GMatchRecord *record, const char *name, size_t len, unsigned int level) +{ + GMatchRecord *result; /* Trouvaille à retourner */ + const char *label; /* Etiquette à manipuler */ + size_t label_len; /* Taille de cette étiquette */ + + result = NULL; + + if (G_IS_KAITAI_ATTRIBUTE(record->creator)) + { + label = g_kaitai_attribute_get_label(G_KAITAI_ATTRIBUTE(record->creator)); + + if (label != NULL) + { + label_len = strlen(label); + + if (label_len == len && strncmp(label, name, len) == 0) + { + result = record; + g_object_ref(G_OBJECT(result)); + } + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à consulter. * +* name = désignation de l'élément recherché. * +* len = taille de cette désignation. * +* level = profondeur maximale à atteindre (fond : 0). * +* * +* Description : Recherche la correspondance associée à un identifiant. * +* * +* Retour : Correspondance trouvée ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *g_match_record_find_by_name(GMatchRecord *record, const char *name, size_t len, unsigned int level) +{ + GMatchRecord *result; /* Trouvaille à retourner */ + GMatchRecordClass *class; /* Classe de l'instance */ + + class = G_MATCH_RECORD_GET_CLASS(record); + + result = class->find(record, name, len, level); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à consulter. * +* name = désignation de l'élément recherché. * +* label = étiquette de l'élément constant à traduire. * +* value = valeur entière correspondante. [OUT] * +* * +* Description : Transforme une énumération en constante entière. * +* * +* Retour : Bilan de l'opération : true si la résolution est réalisée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_match_record_resolve_enum(const GMatchRecord *record, const sized_string_t *name, const sized_string_t *label, resolved_value_t *value) +{ + bool result; /* Bilan à retourner */ + GMatchRecordClass *class; /* Classe de l'instance */ + + class = G_MATCH_RECORD_GET_CLASS(record); + + if (class->resolve == NULL) + result = false; + + else + result = class->resolve(record, name, label, value); + + return result; + +} diff --git a/plugins/kaitai/record.h b/plugins/kaitai/record.h new file mode 100644 index 0000000..7db8187 --- /dev/null +++ b/plugins/kaitai/record.h @@ -0,0 +1,88 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * record.h - prototypes pour la définition d'une correspondance avec un attribut Kaitai + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORD_H +#define _PLUGINS_KAITAI_RECORD_H + + +#include <glib-object.h> + + +#include <analysis/content.h> +#include <arch/vmpa.h> +#include <common/szstr.h> + + + +/* Depuis parser.h : spécification d'un lecteur Kaitai (instance) */ +typedef struct _GKaitaiParser GKaitaiParser; + +/* Depuis expression.h : informations transportées par une expression */ +typedef struct _resolved_value_t resolved_value_t; + + + +#define G_TYPE_MATCH_RECORD g_match_record_get_type() +#define G_MATCH_RECORD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_MATCH_RECORD, GMatchRecord)) +#define G_IS_MATCH_RECORD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_MATCH_RECORD)) +#define G_MATCH_RECORD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_MATCH_RECORD, GMatchRecordClass)) +#define G_IS_MATCH_RECORD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_MATCH_RECORD)) +#define G_MATCH_RECORD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_MATCH_RECORD, GMatchRecordClass)) + + +/* Correspondance entre un attribut et du binaire (instance) */ +typedef struct _GMatchRecord GMatchRecord; + +/* Correspondance entre un attribut et du binaire (classe) */ +typedef struct _GMatchRecordClass GMatchRecordClass; + + +/* Indique le type défini pour une correspondance avec du binaire. */ +GType g_match_record_get_type(void); + +/* Renvoie vers le lecteur à l'origine de la correspondance. */ +GKaitaiParser *g_match_record_get_creator(const GMatchRecord *); + +/* Modifie la référence au créateur de la correspondance. */ +void g_match_record_fix_creator(GMatchRecord *, GKaitaiParser *); + +/* Fournit le contenu lié à une correspondance établie. */ +GBinContent *g_match_record_get_content(const GMatchRecord *); + +/* Calcule ou fournit la zone couverte par une correspondance. */ +void g_match_record_get_range(const GMatchRecord *, mrange_t *); + +/* Lit les octets bruts couverts par une correspondance. */ +void g_match_record_read_raw_bytes(const GMatchRecord *, bin_t **, size_t *); + +#define DIRECT_SEARCH_DEEP_LEVEL 1 + +/* Recherche la correspondance associée à un identifiant. */ +GMatchRecord *g_match_record_find_by_name(GMatchRecord *, const char *, size_t, unsigned int); + +/* Transforme une énumération en constante entière. */ +bool g_match_record_resolve_enum(const GMatchRecord *, const sized_string_t *, const sized_string_t *, resolved_value_t *); + + + +#endif /* _PLUGINS_KAITAI_RECORD_H */ diff --git a/plugins/kaitai/records/Makefile.am b/plugins/kaitai/records/Makefile.am new file mode 100644 index 0000000..3884bfb --- /dev/null +++ b/plugins/kaitai/records/Makefile.am @@ -0,0 +1,23 @@ + +noinst_LTLIBRARIES = libkaitairecords.la + +libkaitairecords_la_SOURCES = \ + bits-int.h \ + bits.h bits.c \ + delayed-int.h \ + delayed.h delayed.c \ + empty-int.h \ + empty.h empty.c \ + group-int.h \ + group.h group.c \ + item-int.h \ + item.h item.c \ + list-int.h \ + list.h list.c + +libkaitairecords_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitairecords_la_SOURCES:%c=) diff --git a/plugins/kaitai/records/bits-int.h b/plugins/kaitai/records/bits-int.h new file mode 100644 index 0000000..7b03911 --- /dev/null +++ b/plugins/kaitai/records/bits-int.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits-int.h - prototypes internes pour la conservation d'un champ de bits entre attribut et binaire + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_BITS_INT_H +#define _PLUGINS_KAITAI_RECORDS_BITS_INT_H + + +#include "bits.h" + + +#include "../record-int.h" + + + +/* Correspondance de bits établie entre un attribut et du binaire (instance) */ +struct _GRecordBitField +{ + GMatchRecord parent; /* A laisser en premier */ + + ext_vmpa_t epos; /* Point de départ */ + uint8_t size; /* Quantité de bits concernés */ + SourceEndian endian; /* Boutisme des données imposé */ + +}; + +/* Correspondance de bits établie entre un attribut et du binaire (classe) */ +struct _GRecordBitFieldClass +{ + GMatchRecordClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une correspondance entre attribut et binaire. */ +bool g_record_bit_field_create(GRecordBitField *, GKaitaiAttribute *, GBinContent *, const ext_vmpa_t *, uint8_t, SourceEndian); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_BITS_INT_H */ diff --git a/plugins/kaitai/records/bits.c b/plugins/kaitai/records/bits.c new file mode 100644 index 0000000..d224112 --- /dev/null +++ b/plugins/kaitai/records/bits.c @@ -0,0 +1,283 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.c - conservation d'un champ de bits entre attribut et binaire + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "bits.h" + + +#include <assert.h> +#include <string.h> + + +#include "bits-int.h" + + + +/* -------------------- DEFINITION D'UNE CORRESPONDANCE UNITAIRE -------------------- */ + + +/* Initialise la classe des correspondances attribut/binaire. */ +static void g_record_bit_field_class_init(GRecordBitFieldClass *); + +/* Initialise une correspondance entre attribut et binaire. */ +static void g_record_bit_field_init(GRecordBitField *); + +/* Supprime toutes les références externes. */ +static void g_record_bit_field_dispose(GRecordBitField *); + +/* Procède à la libération totale de la mémoire. */ +static void g_record_bit_field_finalize(GRecordBitField *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Calcule ou fournit la zone couverte par une correspondance. */ +static void g_record_bit_field_get_range(const GRecordBitField *, mrange_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE CORRESPONDANCE UNITAIRE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une correspondance entre un attribut et du binaire. */ +G_DEFINE_TYPE(GRecordBitField, g_record_bit_field, G_TYPE_MATCH_RECORD); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des correspondances attribut/binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_bit_field_class_init(GRecordBitFieldClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GMatchRecordClass *record; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_record_bit_field_dispose; + object->finalize = (GObjectFinalizeFunc)g_record_bit_field_finalize; + + record = G_MATCH_RECORD_CLASS(klass); + + record->get_range = (get_record_range_fc)g_record_bit_field_get_range; + +} + + +/****************************************************************************** +* * +* Paramètres : field = instance à initialiser. * +* * +* Description : Initialise une correspondance entre attribut et binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_bit_field_init(GRecordBitField *field) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : field = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_bit_field_dispose(GRecordBitField *field) +{ + G_OBJECT_CLASS(g_record_bit_field_parent_class)->dispose(G_OBJECT(field)); + +} + + +/****************************************************************************** +* * +* Paramètres : field = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_bit_field_finalize(GRecordBitField *field) +{ + G_OBJECT_CLASS(g_record_bit_field_parent_class)->finalize(G_OBJECT(field)); + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* epos = tête de lecture avec granularité en bits. * +* size = quantité de bits à prendre en compte. * +* endian = boustime des données à respecter. * +* * +* Description : Crée une nouvelle correspondance entre attribut et binaire. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *g_record_bit_field_new(GKaitaiAttribute *attrib, GBinContent *content, const ext_vmpa_t *epos, uint8_t size, SourceEndian endian) +{ + GMatchRecord *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_RECORD_BIT_FIELD, NULL); + + if (!g_record_bit_field_create(G_RECORD_BIT_FIELD(result), attrib, content, epos, size, endian)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : field = correspondance à initialiser pleinement. * +* attrib = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* epos = tête de lecture avec granularité en bits. * +* size = quantité de bits à prendre en compte. * +* endian = boustime des données à respecter. * +* * +* Description : Met en place une correspondance entre attribut et binaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_bit_field_create(GRecordBitField *field, GKaitaiAttribute *attrib, GBinContent *content, const ext_vmpa_t *epos, uint8_t size, SourceEndian endian) +{ + bool result; /* Bilan à retourner */ + + result = g_match_record_create(G_MATCH_RECORD(field), G_KAITAI_PARSER(attrib), content); + + if (result) + { + copy_evmpa(&field->epos, epos); + field->size = size; + field->endian = endian; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : field = correspondance à consulter. * +* out = valeur à sauvegarder sous une forme générique. [OUT] * +* * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_bit_field_get_value(const GRecordBitField *field, resolved_value_t *out) +{ + bool result; /* Bilan à retourner */ + GKaitaiParser *parser; /* Attribut associé à l'élément*/ + + parser = g_match_record_get_creator(G_MATCH_RECORD(field)); + assert(G_IS_KAITAI_ATTRIBUTE(parser)); + + result = g_kaitai_attribute_read_bit_field_value(G_KAITAI_ATTRIBUTE(parser), + G_MATCH_RECORD(field)->content, + &field->epos, field->size, + field->endian, out); + + g_object_unref(G_OBJECT(parser)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : record = correspondance à consulter. * +* range = zone de couverture déterminée. [OUT] * +* * +* Description : Calcule ou fournit la zone couverte par une correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_bit_field_get_range(const GRecordBitField *record, mrange_t *range) +{ + phys_t len; /* Taille en octets */ + + len = record->size / 8; + + if (record->size % 8 > 0) + len ++; + + init_mrange(range, &record->epos.base, len); + +} diff --git a/plugins/kaitai/records/bits.h b/plugins/kaitai/records/bits.h new file mode 100644 index 0000000..923e8e3 --- /dev/null +++ b/plugins/kaitai/records/bits.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bits.h - prototypes pour la conservation d'un champ de bits entre attribut et binaire + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_BITS_H +#define _PLUGINS_KAITAI_RECORDS_BITS_H + + +#include <glib-object.h> + + +#include "../record.h" +#include "../parsers/attribute.h" + + + +#define G_TYPE_RECORD_BIT_FIELD g_record_bit_field_get_type() +#define G_RECORD_BIT_FIELD(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_BIT_FIELD, GRecordBitField)) +#define G_IS_RECORD_BIT_FIELD(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_BIT_FIELD)) +#define G_RECORD_BIT_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_BIT_FIELD, GRecordBitFieldClass)) +#define G_IS_RECORD_BIT_FIELD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_BIT_FIELD)) +#define G_RECORD_BIT_FIELD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_BIT_FIELD, GRecordBitFieldClass)) + + +/* Correspondance de bits établie entre un attribut et du binaire (instance) */ +typedef struct _GRecordBitField GRecordBitField; + +/* Correspondance de bits établie entre un attribut et du binaire (classe) */ +typedef struct _GRecordBitFieldClass GRecordBitFieldClass; + + +/* Indique le type défini pour une correspondance entre un attribut et du binaire. */ +GType g_record_bit_field_get_type(void); + +/* Crée une nouvelle correspondance entre attribut et binaire. */ +GMatchRecord *g_record_bit_field_new(GKaitaiAttribute *, GBinContent *, const ext_vmpa_t *, uint8_t, SourceEndian); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +bool g_record_bit_field_get_value(const GRecordBitField *, resolved_value_t *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_BITS_H */ diff --git a/plugins/kaitai/records/delayed-int.h b/plugins/kaitai/records/delayed-int.h new file mode 100644 index 0000000..9275500 --- /dev/null +++ b/plugins/kaitai/records/delayed-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * delayed-int.h - prototypes internes pour la conservation d'une instance virtuelle + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_DELAYED_INT_H +#define _PLUGINS_KAITAI_RECORDS_DELAYED_INT_H + + +#include "delayed.h" + + +#include "../record-int.h" + + + +/* Valeur calculée selon des correspondances parallèles (instance) */ +struct _GRecordDelayed +{ + GMatchRecord parent; /* A laisser en premier */ + + kaitai_scope_t locals; /* Sauvegarde de contexte */ + + bool has_value; /* Port d'une valeur directe ? */ + GMatchRecord *real_record; /* Enregistrement effectif */ + +}; + +/* Valeur calculée selon des correspondances parallèles (classe) */ +struct _GRecordDelayedClass +{ + GMatchRecordClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une valeur calculée selon des correspondances. */ +bool g_record_delayed_create(GRecordDelayed *, GKaitaiInstance *, const kaitai_scope_t *, GBinContent *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_DELAYED_INT_H */ diff --git a/plugins/kaitai/records/delayed.c b/plugins/kaitai/records/delayed.c new file mode 100644 index 0000000..8c1395c --- /dev/null +++ b/plugins/kaitai/records/delayed.c @@ -0,0 +1,352 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * delayed.c - conservation d'une correspondance entre attribut et binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "delayed.h" + + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + + +#include "delayed-int.h" +#include "item.h" +#include "../parsers/attribute.h" + + + +/* -------------------- DEFINITION D'UNE CORRESPONDANCE UNITAIRE -------------------- */ + + +/* Initialise la classe des valeurs purement calculées. */ +static void g_record_delayed_class_init(GRecordDelayedClass *); + +/* Initialise une correspondance entre attribut et binaire. */ +static void g_record_delayed_init(GRecordDelayed *); + +/* Supprime toutes les références externes. */ +static void g_record_delayed_dispose(GRecordDelayed *); + +/* Procède à la libération totale de la mémoire. */ +static void g_record_delayed_finalize(GRecordDelayed *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Calcule ou fournit la zone couverte par une correspondance. */ +static void g_record_delayed_get_range(const GRecordDelayed *, mrange_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE CORRESPONDANCE UNITAIRE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une valeur calculée selon des correspondances établies. */ +G_DEFINE_TYPE(GRecordDelayed, g_record_delayed, G_TYPE_MATCH_RECORD); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des valeurs purement calculées. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_delayed_class_init(GRecordDelayedClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GMatchRecordClass *record; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_record_delayed_dispose; + object->finalize = (GObjectFinalizeFunc)g_record_delayed_finalize; + + record = G_MATCH_RECORD_CLASS(klass); + + record->get_range = (get_record_range_fc)g_record_delayed_get_range; + +} + + +/****************************************************************************** +* * +* Paramètres : delayed = instance à initialiser. * +* * +* Description : Initialise une correspondance entre attribut et binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_delayed_init(GRecordDelayed *delayed) +{ + init_record_scope(&delayed->locals, NULL); + + delayed->real_record = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : delayed = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_delayed_dispose(GRecordDelayed *delayed) +{ + reset_record_scope(&delayed->locals); + + G_OBJECT_CLASS(g_record_delayed_parent_class)->dispose(G_OBJECT(delayed)); + +} + + +/****************************************************************************** +* * +* Paramètres : delayed = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_delayed_finalize(GRecordDelayed *delayed) +{ + G_OBJECT_CLASS(g_record_delayed_parent_class)->finalize(G_OBJECT(delayed)); + +} + + +/****************************************************************************** +* * +* Paramètres : inst = analyseur à l'origine de la correspondance. * +* locals = correspondances courantes pour résolutions. * +* content = contenu binaire lié à la correspondance. * +* * +* Description : Crée une nouvelle valeur calculée à partir d'une instance. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRecordDelayed *g_record_delayed_new(GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content) +{ + GRecordDelayed *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_RECORD_DELAYED, NULL); + + if (!g_record_delayed_create(result, inst, locals, content)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : delayed = correspondance à initialiser pleinement. * +* inst = analyseur à l'origine de la correspondance. * +* locals = correspondances courantes pour résolutions. * +* content = contenu binaire lié à la correspondance. * +* * +* Description : Met en place une valeur calculée à partir d'une instance. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_delayed_create(GRecordDelayed *delayed, GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content) +{ + bool result; /* Bilan à retourner */ + + result = g_match_record_create(G_MATCH_RECORD(delayed), G_KAITAI_PARSER(inst), content); + + if (result) + copy_record_scope(&delayed->locals, locals); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : delayed = correspondance à consulter. * +* out = valeur à sauvegarder sous forme générique. [OUT] * +* * +* Description : Détermine la valeur d'un élément Kaitai calculé. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_delayed_compute_value(GRecordDelayed *delayed, resolved_value_t *out) +{ + bool result; /* Bilan à retourner */ + GKaitaiParser *parser; /* Instance liée à l'élément */ + + parser = g_match_record_get_creator(G_MATCH_RECORD(delayed)); + assert(G_IS_KAITAI_ATTRIBUTE(parser)); + + if (G_MATCH_RECORD(delayed)->content == NULL) + result = g_kaitai_instance_compute_value(G_KAITAI_INSTANCE(parser), + &delayed->locals, + out); + + else + { + if (delayed->real_record == NULL) + delayed->real_record = g_kaitai_instance_compute_real_record(G_KAITAI_INSTANCE(parser), + &delayed->locals, + G_MATCH_RECORD(delayed)->content); + + if (delayed->real_record == NULL) + result = false; + + else + { + assert(G_IS_RECORD_ITEM(delayed->real_record)); + result = g_record_item_get_value(G_RECORD_ITEM(delayed->real_record), out); + } + + } + + g_object_unref(G_OBJECT(parser)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : delayed = correspondance à consulter. * +* out = valeur à sauvegarder sous forme générique. [OUT] * +* * +* Description : Détermine et ajuste la valeur d'un élément Kaitai calculé. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_delayed_compute_and_aggregate_value(GRecordDelayed *delayed, resolved_value_t *out) +{ + bool result; /* Bilan à retourner */ + sized_string_t converted; /* Conversion finale ? */ + + result = g_record_delayed_compute_value(delayed, out); + + if (result) + { + /** + * Lorsque c'est possible, les tableaux Kaitai sont transformés en série + * d'octets. + * + * Même si les tableaux ont une grande portée en interne des règles + * Kaitai (par exemple pour constituer une table de constantes de + * référence), il en est différemment à l'extérieur du processus de + * traitement : les tableaux sont le plus souvent destinés à manipuler + * les octets représentés directement (par exemple : + * "contents: [0xca, 0xfe, 0xba, 0xbe]"). + * + * Pour les valeurs d'instance dont le type n'est pas explicite, + * le choix est fait de tenter de simplifier la vie de l'utilisateur + * en lui fournissant directement les octets qu'il attend probablement + * plutôt qu'un tableau contenant des octets à extraire. + */ + + if (out->type == GVT_ARRAY) + { + if (g_kaitai_array_convert_to_bytes(out->array, &converted)) + { + EXIT_RESOLVED_VALUE(*out); + + out->bytes = converted; + out->type = GVT_BYTES; + + } + + } + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : delayed = correspondance à consulter. * +* range = zone de couverture déterminée. [OUT] * +* * +* Description : Calcule ou fournit la zone couverte par une correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_delayed_get_range(const GRecordDelayed *delayed, mrange_t *range) +{ + copy_mrange(range, UNUSED_MRANGE_PTR); + +} diff --git a/plugins/kaitai/records/delayed.h b/plugins/kaitai/records/delayed.h new file mode 100644 index 0000000..e88bb6c --- /dev/null +++ b/plugins/kaitai/records/delayed.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * delayed.h - prototypes pour la conservation d'une correspondance entre attribut et binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_DELAYED_H +#define _PLUGINS_KAITAI_RECORDS_DELAYED_H + + +#include <glib-object.h> + + +#include "../record.h" +#include "../parsers/instance.h" + + + +#define G_TYPE_RECORD_DELAYED g_record_delayed_get_type() +#define G_RECORD_DELAYED(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_DELAYED, GRecordDelayed)) +#define G_IS_RECORD_DELAYED(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_DELAYED)) +#define G_RECORD_DELAYED_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_DELAYED, GRecordDelayedClass)) +#define G_IS_RECORD_DELAYED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_DELAYED)) +#define G_RECORD_DELAYED_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_DELAYED, GRecordDelayedClass)) + + +/* Valeur calculée selon des correspondances parallèles (instance) */ +typedef struct _GRecordDelayed GRecordDelayed; + +/* Valeur calculée selon des correspondances parallèles (classe) */ +typedef struct _GRecordDelayedClass GRecordDelayedClass; + + +/* Indique le type défini pour une valeur calculée selon des correspondances établies. */ +GType g_record_delayed_get_type(void); + +/* Crée une nouvelle valeur calculée à partir d'une instance. */ +GRecordDelayed *g_record_delayed_new(GKaitaiInstance *, const kaitai_scope_t *, GBinContent *); + +/* Détermine la valeur d'un élément Kaitai entier calculé. */ +bool g_record_delayed_compute_value(GRecordDelayed *, resolved_value_t *); + +/* Détermine et ajuste la valeur d'un élément Kaitai calculé. */ +bool g_record_delayed_compute_and_aggregate_value(GRecordDelayed *, resolved_value_t *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_DELAYED_H */ diff --git a/plugins/kaitai/records/empty-int.h b/plugins/kaitai/records/empty-int.h new file mode 100644 index 0000000..2c6cefa --- /dev/null +++ b/plugins/kaitai/records/empty-int.h @@ -0,0 +1,57 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * empty-int.h - prototypes internes pour la notification d'une absence de correspondance attendue + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_EMPTY_INT_H +#define _PLUGINS_KAITAI_RECORDS_EMPTY_INT_H + + +#include "empty.h" + + +#include "../record-int.h" + + + +/* Marque d'une zone de correspondance vide (instance) */ +struct _GRecordEmpty +{ + GMatchRecord parent; /* A laisser en premier */ + + vmpa2t pos; /* Début d'une zone vide */ + +}; + +/* Marque d'une zone de correspondance vide (classe) */ +struct _GRecordEmptyClass +{ + GMatchRecordClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une zone de correspondance vide. */ +bool g_record_empty_create(GRecordEmpty *, GKaitaiParser *, GBinContent *, const vmpa2t *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_EMPTY_INT_H */ diff --git a/plugins/kaitai/records/empty.c b/plugins/kaitai/records/empty.c new file mode 100644 index 0000000..e5121e1 --- /dev/null +++ b/plugins/kaitai/records/empty.c @@ -0,0 +1,236 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * empty.c - conservation d'une correspondance entre attribut et binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "empty.h" + + +#include <assert.h> +#include <stdarg.h> +#include <string.h> + + +#include "empty-int.h" + + + +/* ------------------ DEFINITION D'UNE ZONE DE CORRESPONDANCE VIDE ------------------ */ + + +/* Initialise la classe des zones de correspondance vides. */ +static void g_record_empty_class_init(GRecordEmptyClass *); + +/* Initialise une zone de correspondance vide. */ +static void g_record_empty_init(GRecordEmpty *); + +/* Supprime toutes les références externes. */ +static void g_record_empty_dispose(GRecordEmpty *); + +/* Procède à la libération totale de la mémoire. */ +static void g_record_empty_finalize(GRecordEmpty *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Calcule ou fournit la zone couverte par une correspondance. */ +static void g_record_empty_get_range(const GRecordEmpty *, mrange_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE ZONE DE CORRESPONDANCE VIDE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une zone de correspondance vide. */ +G_DEFINE_TYPE(GRecordEmpty, g_record_empty, G_TYPE_MATCH_RECORD); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des zones de correspondance vides. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_empty_class_init(GRecordEmptyClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GMatchRecordClass *record; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_record_empty_dispose; + object->finalize = (GObjectFinalizeFunc)g_record_empty_finalize; + + record = G_MATCH_RECORD_CLASS(klass); + + record->get_range = (get_record_range_fc)g_record_empty_get_range; + +} + + +/****************************************************************************** +* * +* Paramètres : empty = instance à initialiser. * +* * +* Description : Initialise une zone de correspondance vide. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_empty_init(GRecordEmpty *empty) +{ + init_vmpa(&empty->pos, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); + +} + + +/****************************************************************************** +* * +* Paramètres : empty = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_empty_dispose(GRecordEmpty *empty) +{ + G_OBJECT_CLASS(g_record_empty_parent_class)->dispose(G_OBJECT(empty)); + +} + + +/****************************************************************************** +* * +* Paramètres : empty = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_empty_finalize(GRecordEmpty *empty) +{ + G_OBJECT_CLASS(g_record_empty_parent_class)->finalize(G_OBJECT(empty)); + +} + + +/****************************************************************************** +* * +* Paramètres : parser = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* pos = emplacement de la zone vide à construire. * +* * +* Description : Crée une zone de correspondance vide à une position donnée. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRecordEmpty *g_record_empty_new(GKaitaiParser *parser, GBinContent *content, const vmpa2t *pos) +{ + GRecordEmpty *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_RECORD_EMPTY, NULL); + + if (!g_record_empty_create(result, parser, content, pos)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : empty = correspondance à initialiser pleinement. * +* parser = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* pos = emplacement de la zone vide à construire. * +* * +* Description : Met en place une zone de correspondance vide. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_empty_create(GRecordEmpty *empty, GKaitaiParser *parser, GBinContent *content, const vmpa2t *pos) +{ + bool result; /* Bilan à retourner */ + + result = g_match_record_create(G_MATCH_RECORD(empty), parser, content); + + if (result) + copy_vmpa(&empty->pos, pos); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : empty = correspondance à consulter. * +* range = zone de couverture déterminée. [OUT] * +* * +* Description : Calcule ou fournit la zone couverte par une correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_empty_get_range(const GRecordEmpty *empty, mrange_t *range) +{ + init_mrange(range, &empty->pos, 0); + +} diff --git a/plugins/kaitai/records/empty.h b/plugins/kaitai/records/empty.h new file mode 100644 index 0000000..4e89b62 --- /dev/null +++ b/plugins/kaitai/records/empty.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * empty.h - prototypes pour la notification d'une absence de correspondance attendue + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_EMPTY_H +#define _PLUGINS_KAITAI_RECORDS_EMPTY_H + + +#include <glib-object.h> + + +#include "../record.h" + + + +#define G_TYPE_RECORD_EMPTY g_record_empty_get_type() +#define G_RECORD_EMPTY(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_EMPTY, GRecordEmpty)) +#define G_IS_RECORD_EMPTY(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_EMPTY)) +#define G_RECORD_EMPTY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_EMPTY, GRecordEmptyClass)) +#define G_IS_RECORD_EMPTY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_EMPTY)) +#define G_RECORD_EMPTY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_EMPTY, GRecordEmptyClass)) + + +/* Marque d'une zone de correspondance vide (instance) */ +typedef struct _GRecordEmpty GRecordEmpty; + +/* Marque d'une zone de correspondance vide (classe) */ +typedef struct _GRecordEmptyClass GRecordEmptyClass; + + +/* Indique le type défini pour une zone de correspondance vide. */ +GType g_record_empty_get_type(void); + +/* Crée une zone de correspondance vide à une position donnée. */ +GRecordEmpty *g_record_empty_new(GKaitaiParser *, GBinContent *, const vmpa2t *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_EMPTY_H */ diff --git a/plugins/kaitai/records/group-int.h b/plugins/kaitai/records/group-int.h new file mode 100644 index 0000000..1fd0162 --- /dev/null +++ b/plugins/kaitai/records/group-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * group-int.h - prototypes internes pour la conservation d'un groupe de correspondance avec du binaire + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_GROUP_INT_H +#define _PLUGINS_KAITAI_RECORDS_GROUP_INT_H + + +#include "group.h" + + +#include "../record-int.h" + + + +/* Groupe de correspondances établies entre attributs et binaire (instance) */ +struct _GRecordGroup +{ + GMatchRecord parent; /* A laisser en premier */ + + GMatchRecord **children; /* Sous-correspondances */ + size_t count; /* Taille de cette série */ + +}; + +/* Groupe de correspondances établies entre attributs et binaire (classe) */ +struct _GRecordGroupClass +{ + GMatchRecordClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une série de correspondances attribut/binaire. */ +bool g_record_group_create(GRecordGroup *, GKaitaiStruct *, GBinContent *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_GROUP_INT_H */ diff --git a/plugins/kaitai/records/group.c b/plugins/kaitai/records/group.c new file mode 100644 index 0000000..13327c8 --- /dev/null +++ b/plugins/kaitai/records/group.c @@ -0,0 +1,382 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * group.c - conservation d'un groupe de correspondance avec du binaire + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "group.h" + + +#include <malloc.h> + + +#include "group-int.h" +#include "../parsers/attribute.h" + + + +/* ------------------ DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES ------------------ */ + + +/* Initialise la classe des groupes de correspondances. */ +static void g_record_group_class_init(GRecordGroupClass *); + +/* Initialise une série de correspondances attributs/binaire. */ +static void g_record_group_init(GRecordGroup *); + +/* Supprime toutes les références externes. */ +static void g_record_group_dispose(GRecordGroup *); + +/* Procède à la libération totale de la mémoire. */ +static void g_record_group_finalize(GRecordGroup *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Calcule ou fournit la zone couverte par une correspondance. */ +static void g_record_group_get_range(const GRecordGroup *, mrange_t *); + +/* Recherche la correspondance associée à un identifiant. */ +static GMatchRecord *g_record_group_find_by_name(GRecordGroup *, const char *, size_t, unsigned int); + +/* Transforme une énumération en constante entière. */ +static bool g_record_group_resolve_enum(const GRecordGroup *, const sized_string_t *, const sized_string_t *, resolved_value_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une série de correspondances entre attributes et binaire. */ +G_DEFINE_TYPE(GRecordGroup, g_record_group, G_TYPE_MATCH_RECORD); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des groupes de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_group_class_init(GRecordGroupClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GMatchRecordClass *record; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_record_group_dispose; + object->finalize = (GObjectFinalizeFunc)g_record_group_finalize; + + record = G_MATCH_RECORD_CLASS(klass); + + record->get_range = (get_record_range_fc)g_record_group_get_range; + record->find = (find_record_by_name_fc)g_record_group_find_by_name; + record->resolve = (resolve_record_enum_fc)g_record_group_resolve_enum; + +} + + +/****************************************************************************** +* * +* Paramètres : group = instance à initialiser. * +* * +* Description : Initialise une série de correspondances attributs/binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_group_init(GRecordGroup *group) +{ + group->children = NULL; + group->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : group = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_group_dispose(GRecordGroup *group) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < group->count; i++) + g_clear_object(&group->children[i]); + + G_OBJECT_CLASS(g_record_group_parent_class)->dispose(G_OBJECT(group)); + +} + + +/****************************************************************************** +* * +* Paramètres : group = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_group_finalize(GRecordGroup *group) +{ + if (group->children != NULL) + free(group->children); + + G_OBJECT_CLASS(g_record_group_parent_class)->finalize(G_OBJECT(group)); + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu binaire lié à la correspondance. * +* kstruct = analyseur à l'origine de la correspondance. * +* * +* Description : Crée une nouvelle série de correspondances attribut/binaire. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRecordGroup *g_record_group_new(GKaitaiStruct *kstruct, GBinContent *content) +{ + GRecordGroup *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_RECORD_GROUP, NULL); + + if (!g_record_group_create(result, kstruct, content)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : group = correspondance à initialiser pleinement. * +* kstruct = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* * +* Description : Met en place une série de correspondances attribut/binaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_group_create(GRecordGroup *group, GKaitaiStruct *kstruct, GBinContent *content) +{ + bool result; /* Bilan à retourner */ + + result = g_match_record_create(G_MATCH_RECORD(group), G_KAITAI_PARSER(kstruct), content); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : group = ensemble de correspondances attribut/binaire. * +* record = sous-corresponde à intégrer. * +* * +* Description : Ajoute une correspondance supplémentaire à une série. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_record_group_add_record(GRecordGroup *group, GMatchRecord *record) +{ + group->children = realloc(group->children, ++group->count * sizeof(GMatchRecord)); + + group->children[group->count - 1] = record; + g_object_ref(G_OBJECT(record)); + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : group = correspondance à consulter. * +* range = zone de couverture déterminée. [OUT] * +* * +* Description : Calcule ou fournit la zone couverte par une correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_group_get_range(const GRecordGroup *group, mrange_t *range) +{ + vmpa2t start; /* Position de départ */ + mrange_t range_0; /* Première zone couverte */ + mrange_t range_n; /* Dernière zone couverte */ + vmpa2t end; /* Position de d'arrivée */ + phys_t length; /* Taille de zone couverte */ + + if (group->count == 0) + { + init_vmpa(&start, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); + init_mrange(range, &start, VMPA_NO_PHYSICAL); + } + + else + { + g_match_record_get_range(group->children[0], &range_0); + g_match_record_get_range(group->children[group->count - 1], &range_n); + + copy_vmpa(&start, get_mrange_addr(&range_0)); + + compute_mrange_end_addr(&range_n, &end); + length = compute_vmpa_diff(&start, &end); + + init_mrange(range, &start, length); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : group = ensemble de correspondances attribut/binaire. * +* name = désignation de l'élément recherché. * +* len = taille de cette désignation. * +* level = profondeur maximale à atteindre (fond : 0). * +* * +* Description : Recherche la correspondance associée à un identifiant. * +* * +* Retour : Correspondance trouvée ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GMatchRecord *g_record_group_find_by_name(GRecordGroup *group, const char *name, size_t len, unsigned int level) +{ + GMatchRecord *result; /* Correspondance à renvoyer */ + GMatchRecordClass *class; /* Classe parente normalisée */ + size_t i; /* Boucle de parcours */ + + class = G_MATCH_RECORD_CLASS(g_record_group_parent_class); + + /** + * Le cas d'un type utilisateur peut rattacher un attribut Kaitai à un groupe... + */ + result = class->find(G_MATCH_RECORD(group), name, len, level); + + if (level > 0) + { + level--; + + for (i = 0; i < group->count && result == NULL; i++) + result = g_match_record_find_by_name(group->children[i], name, len, level); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : group = ensemble de correspondances attribut/binaire. * +* name = désignation de l'élément recherché. * +* label = étiquette de l'élément constant à traduire. * +* value = valeur entière correspondante. [OUT] * +* * +* Description : Transforme une énumération en constante entière. * +* * +* Retour : Bilan de l'opération : true si la résolution est réalisée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_record_group_resolve_enum(const GRecordGroup *group, const sized_string_t *name, const sized_string_t *label, resolved_value_t *value) +{ + bool result; /* Bilan à retourner */ + GMatchRecord *base; /* Autre version du groupe */ + size_t i; /* Boucle de parcours */ + GKaitaiEnum *kenum; /* Enumération à consulter */ + + result = false; + + base = G_MATCH_RECORD(group); + + if (G_IS_KAITAI_STRUCT(base->creator)) + { + kenum = g_kaitai_structure_get_enum(G_KAITAI_STRUCT(base->creator), name); + + if (kenum != NULL) + { + result = g_kaitai_enum_find_value(kenum, label, value); + g_object_unref(G_OBJECT(kenum)); + } + + } + + for (i = 0; i < group->count && !result; i++) + result = g_match_record_resolve_enum(group->children[i], name, label, value); + + return result; + +} diff --git a/plugins/kaitai/records/group.h b/plugins/kaitai/records/group.h new file mode 100644 index 0000000..454dade --- /dev/null +++ b/plugins/kaitai/records/group.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * group.h - prototypes pour la conservation d'un groupe de correspondance avec du binaire + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_GROUP_H +#define _PLUGINS_KAITAI_RECORDS_GROUP_H + + +#include <glib-object.h> + + +#include <analysis/content.h> + + +#include "../record.h" +#include "../parsers/struct.h" + + + +#define G_TYPE_RECORD_GROUP g_record_group_get_type() +#define G_RECORD_GROUP(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_GROUP, GRecordGroup)) +#define G_IS_RECORD_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_GROUP)) +#define G_RECORD_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_GROUP, GRecordGroupClass)) +#define G_IS_RECORD_GROUP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_GROUP)) +#define G_RECORD_GROUP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_GROUP, GRecordGroupClass)) + + +/* Groupe de correspondances établies entre attributs et binaire (instance) */ +typedef struct _GRecordGroup GRecordGroup; + +/* Groupe de correspondances établies entre attributs et binaire (classe) */ +typedef struct _GRecordGroupClass GRecordGroupClass; + + +/* Indique le type défini pour une série de correspondances entre attributes et binaire. */ +GType g_record_group_get_type(void); + +/* Crée une nouvelle série de correspondances attribut/binaire. */ +GRecordGroup *g_record_group_new(GKaitaiStruct *, GBinContent *); + +/* Ajoute une correspondance supplémentaire à une série. */ +void g_record_group_add_record(GRecordGroup *, GMatchRecord *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_GROUP_H */ diff --git a/plugins/kaitai/records/item-int.h b/plugins/kaitai/records/item-int.h new file mode 100644 index 0000000..56e0a41 --- /dev/null +++ b/plugins/kaitai/records/item-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item-int.h - prototypes internes pour la conservation d'une correspondance entre attribut et binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_ITEM_INT_H +#define _PLUGINS_KAITAI_RECORDS_ITEM_INT_H + + +#include "item.h" + + +#include "../record-int.h" + + + +/* Correspondance établie entre un attribut et du binaire (instance) */ +struct _GRecordItem +{ + GMatchRecord parent; /* A laisser en premier */ + + mrange_t range; /* Zone de binaire couverte */ + SourceEndian endian; /* Boutisme des données imposé */ + +}; + +/* Correspondance établie entre un attribut et du binaire (classe) */ +struct _GRecordItemClass +{ + GMatchRecordClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une correspondance entre attribut et binaire. */ +bool g_record_item_create(GRecordItem *, GKaitaiAttribute *, GBinContent *, const mrange_t *, SourceEndian); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_ITEM_INT_H */ diff --git a/plugins/yaml/scalar.c b/plugins/kaitai/records/item.c index 1dd5989..0bcf9f7 100644 --- a/plugins/yaml/scalar.c +++ b/plugins/kaitai/records/item.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * scalar.c - noeud Yaml de type "scalar" + * item.c - conservation d'une correspondance entre attribut et binaire * * Copyright (C) 2019 Cyrille Bagard * @@ -21,61 +21,56 @@ */ -#include "scalar.h" +#include "item.h" -#include <malloc.h> +#include <assert.h> #include <string.h> -#include "node-int.h" +#include "item-int.h" -/* Noeud d'une arborescence au format Yaml (instance) */ -struct _GYamlScalar -{ - GYamlNode parent; /* A laisser en premier */ +/* -------------------- DEFINITION D'UNE CORRESPONDANCE UNITAIRE -------------------- */ - GYamlLine *key; /* Clef principale du noeud */ - GYamlCollection *collection; /* Collection de noeuds */ -}; +/* Initialise la classe des correspondances attribut/binaire. */ +static void g_record_item_class_init(GRecordItemClass *); -/* Noeud d'une arborescence au format Yaml (classe) */ -struct _GYamlScalarClass -{ - GYamlNodeClass parent; /* A laisser en premier */ +/* Initialise une correspondance entre attribut et binaire. */ +static void g_record_item_init(GRecordItem *); + +/* Supprime toutes les références externes. */ +static void g_record_item_dispose(GRecordItem *); -}; +/* Procède à la libération totale de la mémoire. */ +static void g_record_item_finalize(GRecordItem *); -/* Initialise la classe des noeuds d'arborescence Yaml. */ -static void g_yaml_scalar_class_init(GYamlScalarClass *); -/* Initialise une instance de noeud d'arborescence Yaml. */ -static void g_yaml_scalar_init(GYamlScalar *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ -/* Supprime toutes les références externes. */ -static void g_yaml_scalar_dispose(GYamlScalar *); -/* Procède à la libération totale de la mémoire. */ -static void g_yaml_scalar_finalize(GYamlScalar *); +/* Calcule ou fournit la zone couverte par une correspondance. */ +static void g_record_item_get_range(const GRecordItem *, mrange_t *); + -/* Recherche les noeuds correspondant à un chemin. */ -static void g_yaml_scalar_find_by_path(const GYamlScalar *, const char *, bool, GYamlNode ***, size_t *); +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE CORRESPONDANCE UNITAIRE */ +/* ---------------------------------------------------------------------------------- */ -/* Indique le type défini pour un noeud d'arborescence Yaml. */ -G_DEFINE_TYPE(GYamlScalar, g_yaml_scalar, G_TYPE_YAML_NODE); +/* Indique le type défini pour une correspondance entre un attribut et du binaire. */ +G_DEFINE_TYPE(GRecordItem, g_record_item, G_TYPE_MATCH_RECORD); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des noeuds d'arborescence Yaml. * +* Description : Initialise la classe des correspondances attribut/binaire. * * * * Retour : - * * * @@ -83,28 +78,28 @@ G_DEFINE_TYPE(GYamlScalar, g_yaml_scalar, G_TYPE_YAML_NODE); * * ******************************************************************************/ -static void g_yaml_scalar_class_init(GYamlScalarClass *klass) +static void g_record_item_class_init(GRecordItemClass *klass) { GObjectClass *object; /* Autre version de la classe */ - GYamlNodeClass *node; /* Version parente de classe */ + GMatchRecordClass *record; /* Version parente de la classe*/ object = G_OBJECT_CLASS(klass); - object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_scalar_dispose; - object->finalize = (GObjectFinalizeFunc)g_yaml_scalar_finalize; + object->dispose = (GObjectFinalizeFunc/* ! */)g_record_item_dispose; + object->finalize = (GObjectFinalizeFunc)g_record_item_finalize; - node = G_YAML_NODE_CLASS(klass); + record = G_MATCH_RECORD_CLASS(klass); - node->find = (find_yaml_node_fc)g_yaml_scalar_find_by_path; + record->get_range = (get_record_range_fc)g_record_item_get_range; } /****************************************************************************** * * -* Paramètres : node = instance à initialiser. * +* Paramètres : item = instance à initialiser. * * * -* Description : Initialise une instance de noeud d'arborescence Yaml. * +* Description : Initialise une correspondance entre attribut et binaire. * * * * Retour : - * * * @@ -112,17 +107,16 @@ static void g_yaml_scalar_class_init(GYamlScalarClass *klass) * * ******************************************************************************/ -static void g_yaml_scalar_init(GYamlScalar *node) +static void g_record_item_init(GRecordItem *item) { - node->key = NULL; - node->collection = NULL; + copy_mrange(&item->range, UNUSED_MRANGE_PTR); } /****************************************************************************** * * -* Paramètres : node = instance d'objet GLib à traiter. * +* Paramètres : item = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -132,20 +126,16 @@ static void g_yaml_scalar_init(GYamlScalar *node) * * ******************************************************************************/ -static void g_yaml_scalar_dispose(GYamlScalar *node) +static void g_record_item_dispose(GRecordItem *item) { - g_clear_object(&node->key); - - g_clear_object(&node->collection); - - G_OBJECT_CLASS(g_yaml_scalar_parent_class)->dispose(G_OBJECT(node)); + G_OBJECT_CLASS(g_record_item_parent_class)->dispose(G_OBJECT(item)); } /****************************************************************************** * * -* Paramètres : node = instance d'objet GLib à traiter. * +* Paramètres : item = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -155,18 +145,21 @@ static void g_yaml_scalar_dispose(GYamlScalar *node) * * ******************************************************************************/ -static void g_yaml_scalar_finalize(GYamlScalar *node) +static void g_record_item_finalize(GRecordItem *item) { - G_OBJECT_CLASS(g_yaml_scalar_parent_class)->finalize(G_OBJECT(node)); + G_OBJECT_CLASS(g_record_item_parent_class)->finalize(G_OBJECT(item)); } /****************************************************************************** * * -* Paramètres : key = line Yaml représentant la clef du futur noeud. * +* Paramètres : attrib = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* range = zone couverture par la correspondance. * +* endian = boustime des données à respecter. * * * -* Description : Construit un noeud d'arborescence Yaml. * +* Description : Crée une nouvelle correspondance entre attribut et binaire. * * * * Retour : Instance mise en place ou NULL en cas d'échec. * * * @@ -174,24 +167,14 @@ static void g_yaml_scalar_finalize(GYamlScalar *node) * * ******************************************************************************/ -GYamlScalar *g_yaml_scalar_new(GYamlLine *key) +GRecordItem *g_record_item_new(GKaitaiAttribute *attrib, GBinContent *content, const mrange_t *range, SourceEndian endian) { - GYamlScalar *result; /* Structure à retourner */ + GRecordItem *result; /* Structure à retourner */ - result = g_object_new(G_TYPE_YAML_SCALAR, NULL); + result = g_object_new(G_TYPE_RECORD_ITEM, NULL); - /** - * Le paragraphe "3.2.2.1. Keys Order" des spécifications précise - * qu'une séquence n'est qu'un noeud sans correspondance clef/valeur. - * - * Cette situation doit donc être prise en compte. - */ - - if (key != NULL) - { - result->key = key; - g_object_ref(G_OBJECT(key)); - } + if (!g_record_item_create(result, attrib, content, range, endian)) + g_clear_object(&result); return result; @@ -200,24 +183,33 @@ GYamlScalar *g_yaml_scalar_new(GYamlLine *key) /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* Paramètres : item = correspondance à initialiser pleinement. * +* attrib = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* range = zone couverte par la correspondance. * +* endian = boustime des données à respecter. * * * -* Description : Fournit la ligne principale associée à un noeud. * +* Description : Met en place une correspondance entre attribut et binaire. * * * -* Retour : Ligne Yaml à l'origine du noeud. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -GYamlLine *g_yaml_scalar_get_yaml_line(const GYamlScalar *node) +bool g_record_item_create(GRecordItem *item, GKaitaiAttribute *attrib, GBinContent *content, const mrange_t *range, SourceEndian endian) { - GYamlLine *result; /* Ligne d'origine à renvoyer */ + bool result; /* Bilan à retourner */ + + result = g_match_record_create(G_MATCH_RECORD(item), G_KAITAI_PARSER(attrib), content); + + if (result) + { + copy_mrange(&item->range, range); - result = node->key; + item->endian = endian; - if (result != NULL) - g_object_ref(G_OBJECT(result)); + } return result; @@ -226,62 +218,83 @@ GYamlLine *g_yaml_scalar_get_yaml_line(const GYamlScalar *node) /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à compléter. * -* collec = collection de noeuds Yaml. * +* Paramètres : item = correspondance à consulter. * +* out = tableau d'octets retournés. [OUT] * +* len = taille de ce tableau alloué. [OUT] * * * -* Description : Attache une collection de noeuds Yaml à un noeud. * +* Description : Lit la série d'octets d'un élément Kaitai entier représenté. * * * -* Retour : - * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -void g_yaml_scalar_set_collection(GYamlScalar *node, GYamlCollection *collec) +bool g_record_item_get_truncated_bytes(const GRecordItem *item, bin_t **out, size_t *len) { - g_clear_object(&node->collection); + bool result; /* Bilan à retourner */ + GKaitaiParser *parser; /* Attribut associé à l'élément*/ + + parser = g_match_record_get_creator(G_MATCH_RECORD(item)); + assert(G_IS_KAITAI_ATTRIBUTE(parser)); - g_object_ref_sink(G_OBJECT(collec)); - node->collection = collec; + result = g_kaitai_attribute_read_truncated_bytes(G_KAITAI_ATTRIBUTE(parser), + G_MATCH_RECORD(item)->content, + &item->range, + out, len); + + g_object_unref(G_OBJECT(parser)); + + return result; } /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* Paramètres : item = correspondance à consulter. * +* out = valeur à sauvegarder sous une forme générique. [OUT] * * * -* Description : Fournit une éventuelle collection rattachée à un noeud. * +* Description : Lit la valeur d'un élément Kaitai entier représenté. * * * -* Retour : Collection de noeuds Yaml ou NULL. * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -GYamlCollection *g_yaml_scalar_get_collection(const GYamlScalar *node) +bool g_record_item_get_value(const GRecordItem *item, resolved_value_t *out) { - GYamlCollection *result; /* Collection à renvoyer */ + bool result; /* Bilan à retourner */ + GKaitaiParser *parser; /* Attribut associé à l'élément*/ + + parser = g_match_record_get_creator(G_MATCH_RECORD(item)); + assert(G_IS_KAITAI_ATTRIBUTE(parser)); - result = node->collection; + result = g_kaitai_attribute_read_value(G_KAITAI_ATTRIBUTE(parser), + G_MATCH_RECORD(item)->content, + &item->range, + item->endian, out); - if (result != NULL) - g_object_ref(G_OBJECT(result)); + g_object_unref(G_OBJECT(parser)); return result; } + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* nodes = liste de noeuds avec correspondance établie. [OUT] * -* count = quantité de ces noeuds. [OUT] * +* Paramètres : item = correspondance à consulter. * +* range = zone de couverture déterminée. [OUT] * * * -* Description : Recherche les noeuds correspondant à un chemin. * +* Description : Calcule ou fournit la zone couverte par une correspondance. * * * * Retour : - * * * @@ -289,90 +302,8 @@ GYamlCollection *g_yaml_scalar_get_collection(const GYamlScalar *node) * * ******************************************************************************/ -static void g_yaml_scalar_find_by_path(const GYamlScalar *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count) +static void g_record_item_get_range(const GRecordItem *item, mrange_t *range) { - GYamlLine *line; /* Ligne Yaml liée au noeud */ - const char *key; /* Clef associée au noeud */ - char *next; /* Prochaine partie du chemin */ - size_t cmplen; /* Etendue de la comparaison */ - int ret; /* Bilan d'une comparaison */ - GYamlCollection *collec; /* Collection de noeuds */ - - if (path[0] == '\0') - goto exit; - - line = g_yaml_scalar_get_yaml_line(node); - - /* Correspondance au niveau du noeud ? */ - - if (line != NULL) - { - if (path[0] == '/') - { - path++; - - if (path[0] == '\0') - goto matched; - - } - - key = g_yaml_line_get_key(line); - - next = strchr(path, '/'); - - if (next == NULL) - ret = strcmp(path, key); - - else - { - cmplen = next - path; - - if (cmplen == 0) - goto cont; - - ret = strncmp(path, key, cmplen); - - } - - if (ret != 0) - goto done; - - else if (next != NULL) - { - path += cmplen; - goto cont; - } - - matched: - - *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **)); - - g_object_ref(G_OBJECT(node)); - (*nodes)[*count - 1] = G_YAML_NODE(node); - - goto done; - - } - - cont: - - collec = g_yaml_scalar_get_collection(node); - - if (collec != NULL) - { - _g_yaml_node_find_by_path(G_YAML_NODE(collec), path, prepare, nodes, count); - - g_object_unref(G_OBJECT(collec)); - - } - - done: - - if (line != NULL) - g_object_unref(G_OBJECT(line)); - - exit: - - ; + copy_mrange(range, &item->range); } diff --git a/plugins/kaitai/records/item.h b/plugins/kaitai/records/item.h new file mode 100644 index 0000000..1286a89 --- /dev/null +++ b/plugins/kaitai/records/item.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour la conservation d'une correspondance entre attribut et binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_ITEM_H +#define _PLUGINS_KAITAI_RECORDS_ITEM_H + + +#include <glib-object.h> + + +#include "../record.h" +#include "../parsers/attribute.h" + + + +#define G_TYPE_RECORD_ITEM g_record_item_get_type() +#define G_RECORD_ITEM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_ITEM, GRecordItem)) +#define G_IS_RECORD_ITEM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_ITEM)) +#define G_RECORD_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_ITEM, GRecordItemClass)) +#define G_IS_RECORD_ITEM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_ITEM)) +#define G_RECORD_ITEM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_ITEM, GRecordItemClass)) + + +/* Correspondance établie entre un attribut et du binaire (instance) */ +typedef struct _GRecordItem GRecordItem; + +/* Correspondance établie entre un attribut et du binaire (classe) */ +typedef struct _GRecordItemClass GRecordItemClass; + + +/* Indique le type défini pour une correspondance entre un attribut et du binaire. */ +GType g_record_item_get_type(void); + +/* Crée une nouvelle correspondance entre attribut et binaire. */ +GRecordItem *g_record_item_new(GKaitaiAttribute *, GBinContent *, const mrange_t *, SourceEndian); + +/* Lit la série d'octets d'un élément Kaitai entier représenté. */ +bool g_record_item_get_truncated_bytes(const GRecordItem *, bin_t **, size_t *); + +/* Lit la valeur d'un élément Kaitai entier représenté. */ +bool g_record_item_get_value(const GRecordItem *, resolved_value_t *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_ITEM_H */ diff --git a/plugins/kaitai/records/list-int.h b/plugins/kaitai/records/list-int.h new file mode 100644 index 0000000..88b411d --- /dev/null +++ b/plugins/kaitai/records/list-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list-int.h - prototypes internes pour la conservation d'une liste de correspondance avec du binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_LIST_INT_H +#define _PLUGINS_KAITAI_RECORDS_LIST_INT_H + + +#include "list.h" + + +#include "../record-int.h" + + + +/* Liste de correspondances établies entre attributs et binaire (instance) */ +struct _GRecordList +{ + GMatchRecord parent; /* A laisser en premier */ + + vmpa2t pos; /* Début de zone */ + + GMatchRecord **children; /* Sous-correspondances */ + size_t count; /* Taille de cette série */ + +}; + +/* Liste de correspondances établies entre attributs et binaire (classe) */ +struct _GRecordListClass +{ + GMatchRecordClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une série de correspondances attribut/binaire. */ +bool g_record_list_create(GRecordList *, GKaitaiAttribute *, GBinContent *, const vmpa2t *); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_LIST_INT_H */ diff --git a/plugins/kaitai/records/list.c b/plugins/kaitai/records/list.c new file mode 100644 index 0000000..1a36bf5 --- /dev/null +++ b/plugins/kaitai/records/list.c @@ -0,0 +1,424 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.c - conservation d'une liste de correspondance avec du binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "list.h" + + +#include <assert.h> +#include <malloc.h> + + +#include "list-int.h" + + + +/* ------------------ DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES ------------------ */ + + +/* Initialise la classe des listes de correspondances. */ +static void g_record_list_class_init(GRecordListClass *); + +/* Initialise une série de correspondances attributs/binaire. */ +static void g_record_list_init(GRecordList *); + +/* Supprime toutes les références externes. */ +static void g_record_list_dispose(GRecordList *); + +/* Procède à la libération totale de la mémoire. */ +static void g_record_list_finalize(GRecordList *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Calcule ou fournit la zone couverte par une correspondance. */ +static void g_record_list_get_range(const GRecordList *, mrange_t *); + +/* Recherche la correspondance associée à un identifiant. */ +static GMatchRecord *g_record_list_find_by_name(GRecordList *, const char *, size_t, unsigned int); + +/* Transforme une énumération en constante entière. */ +static bool g_record_list_resolve_enum(const GRecordList *, const sized_string_t *, const sized_string_t *, resolved_value_t *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITION D'UNE SEQUENCE DE CORRESPONDANCES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une série de correspondances entre attributes et binaire. */ +G_DEFINE_TYPE(GRecordList, g_record_list, G_TYPE_MATCH_RECORD); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des listes de correspondances. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_list_class_init(GRecordListClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GMatchRecordClass *record; /* Version parente de la classe*/ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_record_list_dispose; + object->finalize = (GObjectFinalizeFunc)g_record_list_finalize; + + record = G_MATCH_RECORD_CLASS(klass); + + record->get_range = (get_record_range_fc)g_record_list_get_range; + record->find = (find_record_by_name_fc)g_record_list_find_by_name; + record->resolve = (resolve_record_enum_fc)g_record_list_resolve_enum; + +} + + +/****************************************************************************** +* * +* Paramètres : list = instance à initialiser. * +* * +* Description : Initialise une série de correspondances attributs/binaire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_list_init(GRecordList *list) +{ + list->children = NULL; + list->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : list = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_list_dispose(GRecordList *list) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < list->count; i++) + g_clear_object(&list->children[i]); + + G_OBJECT_CLASS(g_record_list_parent_class)->dispose(G_OBJECT(list)); + +} + + +/****************************************************************************** +* * +* Paramètres : list = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_list_finalize(GRecordList *list) +{ + if (list->children != NULL) + free(list->children); + + G_OBJECT_CLASS(g_record_list_parent_class)->finalize(G_OBJECT(list)); + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* pos = début de la zone de couverture de la liste. * +* * +* Description : Crée une nouvelle série de correspondances attribut/binaire. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GRecordList *g_record_list_new(GKaitaiAttribute *attrib, GBinContent *content, const vmpa2t *pos) +{ + GRecordList *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_RECORD_LIST, NULL); + + if (!g_record_list_create(result, attrib, content, pos)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = correspondance à initialiser pleinement. * +* attrib = analyseur à l'origine de la correspondance. * +* content = contenu binaire lié à la correspondance. * +* * +* Description : Met en place une série de correspondances attribut/binaire. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_record_list_create(GRecordList *list, GKaitaiAttribute *attrib, GBinContent *content, const vmpa2t *pos) +{ + bool result; /* Bilan à retourner */ + + result = g_match_record_create(G_MATCH_RECORD(list), G_KAITAI_PARSER(attrib), content); + + if (result) + copy_vmpa(&list->pos, pos); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de correspondances attribut/binaire. * +* * +* Description : Dénombre le nombre de correspondances enregistrées. * +* * +* Retour : Taille de la liste représentée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_record_list_count_records(const GRecordList *list) +{ + size_t result; /* Quantité à retourner */ + + result = list->count; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de correspondances attribut/binaire. * +* record = sous-corresponde à intégrer. * +* * +* Description : Ajoute une correspondance supplémentaire à une série. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_record_list_add_record(GRecordList *list, GMatchRecord *record) +{ + list->children = realloc(list->children, ++list->count * sizeof(GMatchRecord)); + + list->children[list->count - 1] = record; + g_object_ref(G_OBJECT(record)); + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de correspondances attribut/binaire. * +* index = indice de la correspondance visée. * +* * +* Description : Fournit un élément ciblé dans la liste de correspondances. * +* * +* Retour : Instance de correspondance particulière, voire NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *g_record_list_get_record(const GRecordList *list, size_t index) +{ + GMatchRecord *result; /* Instance à retourner */ + + if (index < list->count) + { + result = list->children[index]; + g_object_ref(G_OBJECT(result)); + } + else + result = NULL; + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : list = correspondance à consulter. * +* range = zone de couverture déterminée. [OUT] * +* * +* Description : Calcule ou fournit la zone couverte par une correspondance. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_record_list_get_range(const GRecordList *list, mrange_t *range) +{ + vmpa2t start; /* Position de départ */ + mrange_t range_0; /* Première zone couverte */ + mrange_t range_n; /* Dernière zone couverte */ + vmpa2t end; /* Position de d'arrivée */ + phys_t length; /* Taille de zone couverte */ + + assert(list->count > 0); + + if (list->count == 0) + { + init_vmpa(&start, VMPA_NO_PHYSICAL, VMPA_NO_VIRTUAL); + init_mrange(range, &start, VMPA_NO_PHYSICAL); + } + + else + { + g_match_record_get_range(list->children[0], &range_0); + g_match_record_get_range(list->children[list->count - 1], &range_n); + + copy_vmpa(&start, get_mrange_addr(&range_0)); + + compute_mrange_end_addr(&range_n, &end); + length = compute_vmpa_diff(&start, &end); + + init_mrange(range, &start, length); + + } + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de correspondances attribut/binaire. * +* name = désignation de l'élément recherché. * +* len = taille de cette désignation. * +* level = profondeur maximale à atteindre (fond : 0). * +* * +* Description : Recherche la correspondance associée à un identifiant. * +* * +* Retour : Correspondance trouvée ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GMatchRecord *g_record_list_find_by_name(GRecordList *list, const char *name, size_t len, unsigned int level) +{ + GMatchRecord *result; /* Correspondance à renvoyer */ + GMatchRecordClass *class; /* Classe parente normalisée */ + size_t i; /* Boucle de parcours */ + + class = G_MATCH_RECORD_CLASS(g_record_list_parent_class); + + result = class->find(G_MATCH_RECORD(list), name, len, level); + + if (level > 0) + { + for (i = 0; i < list->count && result == NULL; i++) + result = g_match_record_find_by_name(list->children[i], name, len, level); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : list = ensemble de correspondances attribut/binaire. * +* name = désignation de l'élément recherché. * +* label = étiquette de l'élément constant à traduire. * +* value = valeur entière correspondante. [OUT] * +* * +* Description : Transforme une énumération en constante entière. * +* * +* Retour : Bilan de l'opération : true si la résolution est réalisée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_record_list_resolve_enum(const GRecordList *list, const sized_string_t *name, const sized_string_t *label, resolved_value_t *value) +{ + bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ + + /** + * Comme les types peuvent être sélectionnés dynamiquement, le parcours + * de l'ensemble des sous-noeuds doit être effectué. + */ + + result = false; + + for (i = 0; i < list->count && !result; i++) + result = g_match_record_resolve_enum(list->children[i], name, label, value); + + return result; + +} diff --git a/plugins/kaitai/records/list.h b/plugins/kaitai/records/list.h new file mode 100644 index 0000000..03e593e --- /dev/null +++ b/plugins/kaitai/records/list.h @@ -0,0 +1,71 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - prototypes pour la conservation d'une liste de correspondance avec du binaire + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_RECORDS_LIST_H +#define _PLUGINS_KAITAI_RECORDS_LIST_H + + +#include <glib-object.h> + + +#include <analysis/content.h> + + +#include "../record.h" +#include "../parsers/attribute.h" + + + +#define G_TYPE_RECORD_LIST g_record_list_get_type() +#define G_RECORD_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_RECORD_LIST, GRecordList)) +#define G_IS_RECORD_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_RECORD_LIST)) +#define G_RECORD_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_RECORD_LIST, GRecordListClass)) +#define G_IS_RECORD_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_RECORD_LIST)) +#define G_RECORD_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_RECORD_LIST, GRecordListClass)) + + +/* Liste de correspondances établies entre attributs et binaire (instance) */ +typedef struct _GRecordList GRecordList; + +/* Liste de correspondances établies entre attributs et binaire (classe) */ +typedef struct _GRecordListClass GRecordListClass; + + +/* Indique le type défini pour une série de correspondances entre attributes et binaire. */ +GType g_record_list_get_type(void); + +/* Crée une nouvelle série de correspondances attribut/binaire. */ +GRecordList *g_record_list_new(GKaitaiAttribute *, GBinContent *, const vmpa2t *); + +/* Dénombre le nombre de correspondances enregistrées. */ +size_t g_record_list_count_records(const GRecordList *); + +/* Ajoute une correspondance supplémentaire à une série. */ +void g_record_list_add_record(GRecordList *, GMatchRecord *); + +/* Fournit un élément ciblé dans la liste de correspondances. */ +GMatchRecord *g_record_list_get_record(const GRecordList *, size_t); + + + +#endif /* _PLUGINS_KAITAI_RECORDS_LIST_H */ diff --git a/plugins/kaitai/rost/Makefile.am b/plugins/kaitai/rost/Makefile.am new file mode 100644 index 0000000..c7ea84a --- /dev/null +++ b/plugins/kaitai/rost/Makefile.am @@ -0,0 +1,18 @@ + +noinst_LTLIBRARIES = libkaitairost.la + +libkaitairost_la_SOURCES = \ + browser-int.h \ + browser.h browser.c \ + core.h core.c \ + space-int.h \ + space.h space.c \ + trigger-int.h \ + trigger.h trigger.c + +libkaitairost_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + + +devdir = $(includedir)/chrysalide-$(subdir) + +dev_HEADERS = $(libkaitairost_la_SOURCES:%c=) diff --git a/plugins/kaitai/rost/browser-int.h b/plugins/kaitai/rost/browser-int.h new file mode 100644 index 0000000..4b49680 --- /dev/null +++ b/plugins/kaitai/rost/browser-int.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * browser-int.h - prototypes internes pour le parcours des résultats d'analyse Kaitai pour ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_ROST_BROWSER_INT_H +#define PLUGINS_KAITAI_ROST_BROWSER_INT_H + + +#include <analysis/scan/item-int.h> + + +#include "browser.h" + + + +/* Parcours des résultats d'une analyse Kaitai pour ROST (instance) */ +struct _GKaitaiBrowser +{ + GScanRegisteredItem parent; /* A laisser en premier */ + + char *path; /* Chamin vers l'enregistrement*/ + GMatchRecord *record; /* Correspondance à parcourir */ + +}; + +/* Parcours des résultats d'une analyse Kaitai pour ROST (classe) */ +struct _GKaitaiBrowserClass +{ + GScanRegisteredItemClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un nouveau parcours de correspondances Kaitai. */ +bool g_kaitai_browser_create(GKaitaiBrowser *, const char *, GMatchRecord *); + + + +#endif /* PLUGINS_KAITAI_ROST_BROWSER_INT_H */ diff --git a/plugins/kaitai/rost/browser.c b/plugins/kaitai/rost/browser.c new file mode 100644 index 0000000..159915b --- /dev/null +++ b/plugins/kaitai/rost/browser.c @@ -0,0 +1,478 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * browser.c - accès à des définitions Kaitai depuis ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "browser.h" + + +#include <assert.h> +#include <string.h> + + +#include <analysis/scan/exprs/literal.h> + + +#include "browser-int.h" +#include "../records/bits.h" +#include "../records/delayed.h" +#include "../records/item.h" +#include "../records/list.h" + + + +/* ---------------------- PARCOURS DE CORRESPONDANCES ETABLIES ---------------------- */ + + +/* Initialise la classe des parcours de correspondances Kaitai. */ +static void g_kaitai_browser_class_init(GKaitaiBrowserClass *); + +/* Initialise un parcours de correspondances Kaitai. */ +static void g_kaitai_browser_init(GKaitaiBrowser *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_browser_dispose(GKaitaiBrowser *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_browser_finalize(GKaitaiBrowser *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_kaitai_browser_get_name(const GKaitaiBrowser *); + +/* Lance une résolution d'élément à solliciter. */ +static bool g_kaitai_browser_resolve(GKaitaiBrowser *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **); + +/* Réduit une expression à une forme plus simple. */ +static bool g_kaitai_browser_reduce(GKaitaiBrowser *, GScanContext *, GScanScope *, GScanExpression **); + +/* Effectue une extraction d'élément à partir d'une série. */ +static GObject *g_kaitai_browser_extract_at(GKaitaiBrowser *, const GScanExpression *, GScanContext *, GScanScope *); + + + +/* ---------------------------------------------------------------------------------- */ +/* PARCOURS DE CORRESPONDANCES ETABLIES */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un parcours de correspondances Kaitai pour ROST. */ +G_DEFINE_TYPE(GKaitaiBrowser, g_kaitai_browser, G_TYPE_SCAN_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des parcours de correspondances Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_class_init(GKaitaiBrowserClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_browser_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_browser_finalize; + + registered = G_SCAN_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_kaitai_browser_get_name; + registered->resolve = (resolve_registered_item_fc)g_kaitai_browser_resolve; + registered->reduce = (reduce_registered_item_fc)g_kaitai_browser_reduce; + registered->extract = (extract_registered_item_at)g_kaitai_browser_extract_at; + +} + + +/****************************************************************************** +* * +* Paramètres : browser = instance à initialiser. * +* * +* Description : Initialise un parcours de correspondances Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_init(GKaitaiBrowser *browser) +{ + browser->path = NULL; + browser->record = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : browser = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_dispose(GKaitaiBrowser *browser) +{ + g_clear_object(&browser->record); + + G_OBJECT_CLASS(g_kaitai_browser_parent_class)->dispose(G_OBJECT(browser)); + +} + + +/****************************************************************************** +* * +* Paramètres : browser = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_browser_finalize(GKaitaiBrowser *browser) +{ + if (browser->path != NULL) + free(browser->path); + + G_OBJECT_CLASS(g_kaitai_browser_parent_class)->finalize(G_OBJECT(browser)); + +} + + +/****************************************************************************** +* * +* Paramètres : path = chemin vers l'enregistrement fourni. * +* record = correspondance racine à considérer. * +* * +* Description : Crée un nouveau parcours de correspondances Kaitai. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiBrowser *g_kaitai_browser_new(const char *path, GMatchRecord *record) +{ + GKaitaiBrowser *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_BROWSER, NULL); + + if (!g_kaitai_browser_create(result, path, record)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : browser = encadrement d'un parcours de correspondances. * +* path = chemin vers l'enregistrement fourni. * +* record = correspondance racine à considérer. * +* * +* Description : Met en place un nouveau parcours de correspondances Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_browser_create(GKaitaiBrowser *browser, const char *path, GMatchRecord *record) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (path != NULL) + browser->path = strdup(path); + + browser->record = record; + g_object_ref(G_OBJECT(browser->record)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_kaitai_browser_get_name(const GKaitaiBrowser *item) +{ + char *result; /* Désignation à retourner */ + int ret; /* Statut de construction */ + + if (item->path == NULL) + result = strdup("kaitai://"); + + else + { + ret = asprintf(&result, "kaitai://%s", item->path); + assert(ret > 0); + + if (ret <= 0) + result = strdup("kaitai://???"); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT]* +* * +* Description : Lance une résolution d'élément à solliciter. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_browser_resolve(GKaitaiBrowser *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out) +{ + bool result; /* Bilan à retourner */ + GMatchRecord *found; /* Correspondance trouvée */ + char *path; + int ret; /* Statut de construction */ + + found = g_match_record_find_by_name(item->record, target, strlen(target), 1); + result = (found != NULL); + + if (result) + { + ret = asprintf(&path, "%s.%s", item->path, target); + assert(ret > 0); + + if (ret <= 0) + path = strdup("!?"); + + *out = G_SCAN_REGISTERED_ITEM(g_kaitai_browser_new(path, found)); + + free(path); + g_object_unref(G_OBJECT(found)); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_browser_reduce(GKaitaiBrowser *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + size_t count; /* Décompte total à considérer */ + resolved_value_t value; /* Valeur brute à transformer */ + + if (G_IS_RECORD_LIST(item->record)) + { + count = g_record_list_count_records(G_RECORD_LIST(item->record)); + + *out = g_scan_literal_expression_new(LVT_BOOLEAN, (bool []){ count > 0 }); + + result = true; + + } + + else + { + if (G_IS_RECORD_BIT_FIELD(item->record)) + result = g_record_bit_field_get_value(G_RECORD_BIT_FIELD(item->record), &value); + + else if (G_IS_RECORD_DELAYED(item->record)) + result = g_record_delayed_compute_and_aggregate_value(G_RECORD_DELAYED(item->record), &value); + + else if (G_IS_RECORD_ITEM(item->record)) + result = g_record_item_get_value(G_RECORD_ITEM(item->record), &value); + + else + result = false; + + if (result) + { + switch (value.type) + { + case GVT_UNSIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &value.unsigned_integer); + break; + + case GVT_SIGNED_INTEGER: + *out = g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &value.signed_integer); + break; + + case GVT_FLOAT: + /* TODO */ + break; + + case GVT_BOOLEAN: + *out = g_scan_literal_expression_new(LVT_BOOLEAN, &value.status); + break; + + case GVT_BYTES: + *out = g_scan_literal_expression_new(LVT_STRING, &value.bytes); + break; + + default: + break; + + } + + EXIT_RESOLVED_VALUE(value); + + } + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* index = indice de l'élément à cibler. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* * +* Description : Effectue une extraction d'élément à partir d'une série. * +* * +* Retour : Elément de série obtenu ou NULL si erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GObject *g_kaitai_browser_extract_at(GKaitaiBrowser *item, const GScanExpression *index, GScanContext *ctx, GScanScope *scope) +{ + GObject *result; /* Elément récupéré à renvoyer */ + GScanLiteralExpression *literal; /* Accès direct à l'indice */ + LiteralValueType vtype; /* Type de valeur portée */ + unsigned long long at; /* Valeur concrète du point */ + bool status; /* Bilan d'obtention d'indice */ + GRecordList *list; /* Accès direct à la liste */ + size_t count; /* Décompte total à considérer */ + GMatchRecord *found; /* Correspondance trouvée */ + char *path; + int ret; /* Statut de construction */ + + result = NULL; + + /* Validations préliminaires */ + + if (!G_IS_RECORD_LIST(item->record)) goto exit; + if (!G_IS_SCAN_LITERAL_EXPRESSION(index)) goto exit; + + literal = G_SCAN_LITERAL_EXPRESSION(index); + + vtype = g_scan_literal_expression_get_value_type(literal); + if (vtype != LVT_UNSIGNED_INTEGER) goto exit; + + status = g_scan_literal_expression_get_unsigned_integer_value(literal, &at); + if (!status) goto exit; + + list = G_RECORD_LIST(item->record); + + count = g_record_list_count_records(list); + if (at >= count) goto exit; + + /* Récupération de l'élément visé */ + + found = g_record_list_get_record(list, at); + if (found == NULL) goto exit; + + ret = asprintf(&path, "%s[%llu]", item->path, at); + assert(ret > 0); + + if (ret <= 0) + path = strdup("!?"); + + result = G_OBJECT(g_kaitai_browser_new(path, found)); + + free(path); + g_object_unref(G_OBJECT(found)); + + exit: + + return result; + +} diff --git a/plugins/kaitai/rost/browser.h b/plugins/kaitai/rost/browser.h new file mode 100644 index 0000000..89b9f6f --- /dev/null +++ b/plugins/kaitai/rost/browser.h @@ -0,0 +1,58 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * browser.h - prototypes pour le parcours des résultats d'analyse Kaitai pour ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_ROST_BROWSER_H +#define PLUGINS_KAITAI_ROST_BROWSER_H + + +#include <glib-object.h> + + +#include "../record.h" + + + +#define G_TYPE_KAITAI_BROWSER g_kaitai_browser_get_type() +#define G_KAITAI_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_BROWSER, GKaitaiBrowser)) +#define G_IS_KAITAI_BROWSER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_BROWSER)) +#define G_KAITAI_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_BROWSER, GKaitaiBrowserClass)) +#define G_IS_KAITAI_BROWSER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_BROWSER)) +#define G_KAITAI_BROWSER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_BROWSER, GKaitaiBrowserClass)) + + +/* Parcours des résultats d'une analyse Kaitai pour ROST (instance) */ +typedef struct _GKaitaiBrowser GKaitaiBrowser; + +/* Parcours des résultats d'une analyse Kaitai pour ROST (classe) */ +typedef struct _GKaitaiBrowserClass GKaitaiBrowserClass; + + +/* Indique le type défini pour un parcours de correspondances Kaitai pour ROST. */ +GType g_kaitai_browser_get_type(void); + +/* Crée un nouveau parcours de correspondances Kaitai. */ +GKaitaiBrowser *g_kaitai_browser_new(const char *, GMatchRecord *); + + + +#endif /* PLUGINS_KAITAI_ROST_BROWSER_H */ diff --git a/plugins/kaitai/rost/core.c b/plugins/kaitai/rost/core.c new file mode 100644 index 0000000..8271389 --- /dev/null +++ b/plugins/kaitai/rost/core.c @@ -0,0 +1,66 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - mise à disposition d'un support Kaitai pour ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "core.h" + + +#include <core/global.h> + + +#include "space.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre un support de Kaitai pour ROST. * +* * +* Retour : Bilan du chargement mené. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_kaitai_support_to_rost(void) +{ + bool result; /* Bilan à retourner */ + GScanNamespace *root_ns; /* Espace de noms ROST racine */ + GScanNamespace *kaitai_ns; /* Espace de noms pour Kaitai */ + + result = true; + + root_ns = get_rost_root_namespace(); + + kaitai_ns = g_kaitai_namespace_new(); + + result = g_scan_namespace_register_item(root_ns, G_SCAN_REGISTERED_ITEM(kaitai_ns)); + + g_object_unref(G_OBJECT(kaitai_ns)); + + g_object_unref(G_OBJECT(root_ns)); + + return result; + +} diff --git a/plugins/kaitai/rost/core.h b/plugins/kaitai/rost/core.h new file mode 100644 index 0000000..6f810eb --- /dev/null +++ b/plugins/kaitai/rost/core.h @@ -0,0 +1,37 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour la mise à disposition d'un support Kaitai pour ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_ROST_CORE_H +#define _PLUGINS_KAITAI_ROST_CORE_H + + +#include <stdbool.h> + + + +/* Intègre un support de Kaitai pour ROST. */ +bool add_kaitai_support_to_rost(void); + + + +#endif /* _PLUGINS_KAITAI_ROST_CORE_H */ diff --git a/plugins/kaitai/rost/space-int.h b/plugins/kaitai/rost/space-int.h new file mode 100644 index 0000000..47ec707 --- /dev/null +++ b/plugins/kaitai/rost/space-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space-int.h - prototypes internes pour la définition d'un espace de noms pour les fonctions de scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_ROST_SPACE_INT_H +#define _PLUGINS_KAITAI_ROST_SPACE_INT_H + + +#include "space.h" + + +#include <analysis/scan/space-int.h> + + + +/* Espace de noms avec chargement dynamique de définitions Kaitai (instance) */ +struct _GKaitaiNamespace +{ + GScanNamespace parent; /* A laisser en premier */ + +}; + +/* Espace de noms avec chargement dynamique de définitions Kaitai (classe) */ +struct _GKaitaiNamespaceClass +{ + GScanNamespaceClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un nouvel espace de noms pour scan. */ +bool g_kaitai_namespace_create(GKaitaiNamespace *); + + + +#endif /* _PLUGINS_KAITAI_ROST_SPACE_INT_H */ diff --git a/plugins/kaitai/rost/space.c b/plugins/kaitai/rost/space.c new file mode 100644 index 0000000..ee922d2 --- /dev/null +++ b/plugins/kaitai/rost/space.c @@ -0,0 +1,254 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.c - définition d'un espace de noms pour les fonctions de scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "space.h" + + +#include <string.h> + + +#include "trigger.h" +#include "space-int.h" +#include "../import.h" + + + +/* ------------------------- SOCLE POUR LES ESPACES DE NOMS ------------------------- */ + + +/* Initialise la classe des espaces de noms dynamiques Kaitai. */ +static void g_kaitai_namespace_class_init(GKaitaiNamespaceClass *); + +/* Initialise une instance d'espace de noms dynamiques Kaitai. */ +static void g_kaitai_namespace_init(GKaitaiNamespace *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_namespace_dispose(GKaitaiNamespace *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_namespace_finalize(GKaitaiNamespace *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Lance une résolution d'élément à solliciter. */ +static bool g_kaitai_namespace_resolve(GKaitaiNamespace *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **); + + + +/* ---------------------------------------------------------------------------------- */ +/* SOCLE POUR LES ESPACES DE NOMS */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour une définition d'espace de noms dynamique Kaitai. */ +G_DEFINE_TYPE(GKaitaiNamespace, g_kaitai_namespace, G_TYPE_SCAN_NAMESPACE); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des espaces de noms dynamiques Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_namespace_class_init(GKaitaiNamespaceClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_namespace_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_namespace_finalize; + + registered = G_SCAN_REGISTERED_ITEM_CLASS(klass); + + registered->resolve = (resolve_registered_item_fc)g_kaitai_namespace_resolve; + +} + + +/****************************************************************************** +* * +* Paramètres : space = instance à initialiser. * +* * +* Description : Initialise une instance d'espace de noms dynamiques Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_namespace_init(GKaitaiNamespace *space) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : space = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_namespace_dispose(GKaitaiNamespace *space) +{ + G_OBJECT_CLASS(g_kaitai_namespace_parent_class)->dispose(G_OBJECT(space)); + +} + + +/****************************************************************************** +* * +* Paramètres : space = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_namespace_finalize(GKaitaiNamespace *space) +{ + G_OBJECT_CLASS(g_kaitai_namespace_parent_class)->finalize(G_OBJECT(space)); + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Construit un nouvel espace de noms dynamique pour Kaitai. * +* * +* Retour : Adresse de la structure mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanNamespace *g_kaitai_namespace_new(void) +{ + GScanNamespace *result; /* Instance à retourner */ + + result = g_object_new(G_TYPE_KAITAI_NAMESPACE, NULL); + + if (!g_kaitai_namespace_create(G_KAITAI_NAMESPACE(result))) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : space = instance d'espace de noms à initialiser. * +* name = désignation du futur espace de noms. * +* * +* Description : Met en place un nouvel espace de noms pour scan. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_namespace_create(GKaitaiNamespace *space) +{ + bool result; /* Bilan à retourner */ + + result = g_scan_namespace_create(G_SCAN_NAMESPACE(space), "kaitai"); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT]* +* * +* Description : Lance une résolution d'élément à solliciter. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_namespace_resolve(GKaitaiNamespace *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out) +{ + bool result; /* Bilan à retourner */ + GScanRegisteredItemClass *parent; /* Version de classe parente */ + GKaitaiStruct *kstruct; /* Lecteur de définition */ + + parent = G_SCAN_REGISTERED_ITEM_CLASS(g_kaitai_namespace_parent_class); + + result = parent->resolve(G_SCAN_REGISTERED_ITEM(item), target, ctx, scope, out); + + if (!result) + { + kstruct = load_kaitai_definition(target, NULL); + + if (kstruct != NULL) + { + *out = g_kaitai_trigger_new(kstruct); + result = true; + + g_object_unref(G_OBJECT(kstruct)); + + } + + } + + return result; + +} diff --git a/plugins/kaitai/rost/space.h b/plugins/kaitai/rost/space.h new file mode 100644 index 0000000..5dcea5e --- /dev/null +++ b/plugins/kaitai/rost/space.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.h - prototypes pour la définition d'un espace de noms pour les fonctions de scan + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Foobar. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_ROST_SPACE_H +#define _PLUGINS_KAITAI_ROST_SPACE_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include <analysis/scan/space.h> + + + +#define G_TYPE_KAITAI_NAMESPACE g_kaitai_namespace_get_type() +#define G_KAITAI_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_NAMESPACE, GKaitaiNamespace)) +#define G_IS_KAITAI_NAMESPACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_NAMESPACE)) +#define G_KAITAI_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_NAMESPACE, GKaitaiNamespaceClass)) +#define G_IS_KAITAI_NAMESPACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_NAMESPACE)) +#define G_KAITAI_NAMESPACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_NAMESPACE, GKaitaiNamespaceClass)) + + +/* Espace de noms avec chargement dynamique de définitions Kaitai (instance) */ +typedef struct _GKaitaiNamespace GKaitaiNamespace; + +/* Espace de noms avec chargement dynamique de définitions Kaitai (classe) */ +typedef struct _GKaitaiNamespaceClass GKaitaiNamespaceClass; + + +/* Indique le type défini pour une définition d'espace de noms dynamique Kaitai. */ +GType g_kaitai_namespace_get_type(void); + +/* Construit un nouvel espace de noms dynamique pour Kaitai. */ +GScanNamespace *g_kaitai_namespace_new(void); + + + +#endif /* _PLUGINS_KAITAI_ROST_SPACE_H */ diff --git a/plugins/kaitai/rost/trigger-int.h b/plugins/kaitai/rost/trigger-int.h new file mode 100644 index 0000000..6830cd7 --- /dev/null +++ b/plugins/kaitai/rost/trigger-int.h @@ -0,0 +1,59 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * trigger-int.h - prototypes internes pour l'accès à des définitions Kaitai depuis ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_ROST_TRIGGER_INT_H +#define _PLUGINS_KAITAI_ROST_TRIGGER_INT_H + + +#include <analysis/scan/item-int.h> + + +#include "trigger.h" + + + +/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (instance) */ +struct _GKaitaiTrigger +{ + GScanRegisteredItem parent; /* A laisser en premier */ + + char *name; /* Désignation arbitraire */ + + GKaitaiStruct *kstruct; /* Définition à décliner */ + +}; + +/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (classe) */ +struct _GKaitaiTriggerClass +{ + GScanRegisteredItemClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un accès à une définition Kaitai pour ROST. */ +bool g_kaitai_trigger_create(GKaitaiTrigger *, GKaitaiStruct *); + + + +#endif /* _PLUGINS_KAITAI_ROST_TRIGGER_INT_H */ diff --git a/plugins/kaitai/rost/trigger.c b/plugins/kaitai/rost/trigger.c new file mode 100644 index 0000000..6bb6e5d --- /dev/null +++ b/plugins/kaitai/rost/trigger.c @@ -0,0 +1,320 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * trigger.c - accès à des définitions Kaitai depuis ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "trigger.h" + + +#include <string.h> + + +#include "browser.h" +#include "trigger-int.h" + + + +/* ---------------------- ACCES ET DECLENCHEMENT D'UNE ANALYSE ---------------------- */ + + +/* Initialise la classe des accès aux définitions Kaitai. */ +static void g_kaitai_trigger_class_init(GKaitaiTriggerClass *); + +/* Initialise un accès à une définition Kaitai. */ +static void g_kaitai_trigger_init(GKaitaiTrigger *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_trigger_dispose(GKaitaiTrigger *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_trigger_finalize(GKaitaiTrigger *); + + + +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Indique le nom associé à une expression d'évaluation. */ +static char *g_kaitai_trigger_get_name(const GKaitaiTrigger *); + +/* Lance une résolution d'élément à solliciter. */ +static bool g_kaitai_trigger_resolve(GKaitaiTrigger *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **); + + + +/* ---------------------------------------------------------------------------------- */ +/* ACCES ET DECLENCHEMENT D'UNE ANALYSE */ +/* ---------------------------------------------------------------------------------- */ + + +/* Indique le type défini pour un accès à une définition Kaitai pour ROST. */ +G_DEFINE_TYPE(GKaitaiTrigger, g_kaitai_trigger, G_TYPE_SCAN_REGISTERED_ITEM); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des accès aux définitions Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_trigger_class_init(GKaitaiTriggerClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + GScanRegisteredItemClass *registered; /* Version de classe parente */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_trigger_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_trigger_finalize; + + registered = G_SCAN_REGISTERED_ITEM_CLASS(klass); + + registered->get_name = (get_registered_item_name_fc)g_kaitai_trigger_get_name; + registered->resolve = (resolve_registered_item_fc)g_kaitai_trigger_resolve; + +} + + +/****************************************************************************** +* * +* Paramètres : trigger = instance à initialiser. * +* * +* Description : Initialise un accès à une définition Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_trigger_init(GKaitaiTrigger *trigger) +{ + trigger->name = NULL; + + trigger->kstruct = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : trigger = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_trigger_dispose(GKaitaiTrigger *trigger) +{ + g_clear_object(&trigger->kstruct); + + G_OBJECT_CLASS(g_kaitai_trigger_parent_class)->dispose(G_OBJECT(trigger)); + +} + + +/****************************************************************************** +* * +* Paramètres : trigger = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_trigger_finalize(GKaitaiTrigger *trigger) +{ + if (trigger->name != NULL) + free(trigger->name); + + G_OBJECT_CLASS(g_kaitai_trigger_parent_class)->finalize(G_OBJECT(trigger)); + +} + + +/****************************************************************************** +* * +* Paramètres : kstruct = définition Kaitai à manipuler avec du contenu. * +* * +* Description : Crée un nouvel accès à une définition Kaitai à instancier. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GScanRegisteredItem *g_kaitai_trigger_new(GKaitaiStruct *kstruct) +{ + GScanRegisteredItem *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_TRIGGER, NULL); + + if (!g_kaitai_trigger_create(G_KAITAI_TRIGGER(result), kstruct)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : trigger = lien vers une définition Kaitai à instancier. * +* kstruct = définition Kaitai à manipuler avec du contenu. * +* * +* Description : Met en place un accès à une définition Kaitai pour ROST. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_trigger_create(GKaitaiTrigger *trigger, GKaitaiStruct *kstruct) +{ + bool result; /* Bilan à retourner */ + + result = true; + + trigger->kstruct = kstruct; + g_object_ref(G_OBJECT(trigger->kstruct)); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : trigger = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *g_kaitai_trigger_get_name(const GKaitaiTrigger *trigger) +{ + char *result; /* Désignation à retourner */ + GKaitaiMeta *meta; /* Eventuelles métadonnées */ + const char *id; /* Identifiant de définition */ + + if (trigger->name != NULL) + result = strdup(trigger->name); + + else + { + result = NULL; + + meta = g_kaitai_structure_get_meta(trigger->kstruct); + if (meta == NULL) goto done; + + id = g_kaitai_meta_get_id(meta); + if (id == NULL) goto done; + + result = strdup(id); + + g_object_unref(G_OBJECT(meta)); + + done: + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT]* +* * +* Description : Lance une résolution d'élément à solliciter. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_kaitai_trigger_resolve(GKaitaiTrigger *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out) +{ + bool result; /* Bilan à retourner */ + GKaitaiBrowser *browser; /* Navigateur pour résultats */ + GBinContent *content; /* Contenu binaire à analyser */ + GMatchRecord *record; /* Premier niveau de résultats */ + + browser = g_object_get_data(G_OBJECT(item), "kaitai_browser"); + + if (browser == NULL) + { + content = g_scan_context_get_content(ctx); + + record = g_kaitai_structure_parse(item->kstruct, content); + + g_object_unref(G_OBJECT(content)); + + if (record != NULL) + { + browser = g_kaitai_browser_new(NULL, record); + + g_object_set_data_full(G_OBJECT(item), "kaitai_browser", browser, g_object_unref); + + } + + } + + if (browser == NULL) + result = false; + + else + result = g_scan_registered_item_resolve(G_SCAN_REGISTERED_ITEM(browser), target, ctx, scope, out); + + return result; + +} diff --git a/plugins/kaitai/rost/trigger.h b/plugins/kaitai/rost/trigger.h new file mode 100644 index 0000000..f55e998 --- /dev/null +++ b/plugins/kaitai/rost/trigger.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * trigger.h - prototypes pour l'accès à des définitions Kaitai depuis ROST + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_ROST_TRIGGER_H +#define PLUGINS_KAITAI_ROST_TRIGGER_H + + +#include <glib-object.h> + + +#include <analysis/scan/item.h> + + +#include "../parsers/struct.h" + + + +#define G_TYPE_KAITAI_TRIGGER g_kaitai_trigger_get_type() +#define G_KAITAI_TRIGGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_TRIGGER, GKaitaiTrigger)) +#define G_IS_KAITAI_TRIGGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_TRIGGER)) +#define G_KAITAI_TRIGGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_TRIGGER, GKaitaiTriggerClass)) +#define G_IS_KAITAI_TRIGGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_TRIGGER)) +#define G_KAITAI_TRIGGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_TRIGGER, GKaitaiTriggerClass)) + + +/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (instance) */ +typedef struct _GKaitaiTrigger GKaitaiTrigger; + +/* Accès à une définition et déclenchement d'une analyse Kaitai depuis ROST (classe) */ +typedef struct _GKaitaiTriggerClass GKaitaiTriggerClass; + + +/* Indique le type défini pour un accès à une définition Kaitai pour ROST. */ +GType g_kaitai_trigger_get_type(void); + +/* Crée un nouvel accès à une définition Kaitai à instancier. */ +GScanRegisteredItem *g_kaitai_trigger_new(GKaitaiStruct *); + + + +#endif /* PLUGINS_KAITAI_ROST_TRIGGER_H */ diff --git a/plugins/kaitai/scope.c b/plugins/kaitai/scope.c new file mode 100644 index 0000000..fad8890 --- /dev/null +++ b/plugins/kaitai/scope.c @@ -0,0 +1,257 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope.c - recherches d'éléments de lecture + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "scope.h" + + +#include "parsers/struct.h" + + + +/****************************************************************************** +* * +* Paramètres : locals = contexte de variables locales à initialiser. * +* meta = informations générales à disposition. * +* * +* Description : Initialise un contexte pour correspondances Kaitai établies. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void init_record_scope(kaitai_scope_t *locals, GKaitaiMeta *meta) +{ + locals->meta = meta; + + if (meta != NULL) + g_object_ref(G_OBJECT(meta)); + + locals->root = NULL; + locals->parent = NULL; + locals->last = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = contexte de variables locales à réinitialiser. * +* * +* Description : Vide un contexte de correspondances Kaitai établies. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void reset_record_scope(kaitai_scope_t *locals) +{ + g_clear_object(&locals->meta); + + g_clear_object(&locals->root); + g_clear_object(&locals->parent); + g_clear_object(&locals->last); + +} + + +/****************************************************************************** +* * +* Paramètres : dest = contexte de variables locales à initialiser. * +* src = contexte de variables locales à copier. * +* * +* Description : Copie un contexte de correspondances Kaitai établies. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void copy_record_scope(kaitai_scope_t *dest, const kaitai_scope_t *src) +{ + reset_record_scope(dest); + +#define COPY_SCOPE_ITEM(itm) \ + dest->itm = src->itm; \ + if (dest->itm != NULL) \ + g_object_ref(G_OBJECT(dest->itm)); + + COPY_SCOPE_ITEM(meta); + + COPY_SCOPE_ITEM(root); + COPY_SCOPE_ITEM(parent); + COPY_SCOPE_ITEM(last); + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* * +* Description : Retourne le souvenir d'une correspondance racine. * +* * +* Retour : Dernière correspondance établie ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *get_root_record(const kaitai_scope_t *locals) +{ + GMatchRecord *result; /* Instance à retourner */ + + result = locals->root; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* * +* Description : Retourne le souvenir de la correspondance parente effectuée. * +* * +* Retour : Dernière correspondance établie ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *get_parent_record(const kaitai_scope_t *locals) +{ + GMatchRecord *result; /* Instance à retourner */ + + result = locals->parent; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* record = dernière correspondance établie. * +* * +* Description : Conserve le souvenir de la dernière correspondance effectuée.* +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void remember_last_record(kaitai_scope_t *locals, GMatchRecord *record) +{ + g_clear_object(&locals->last); + + locals->last = record; + + if (record != NULL) + g_object_ref(G_OBJECT(record)); + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* * +* Description : Retourne le souvenir de la dernière correspondance effectuée.* +* * +* Retour : Dernière correspondance établie ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GMatchRecord *get_last_record(const kaitai_scope_t *locals) +{ + GMatchRecord *result; /* Instance à retourner */ + + result = locals->last; + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : locals = variables locales pour les résolutions de types. * +* name = désignation du type particulier ciblé. * +* * +* Description : Recherche la définition d'un type nouveau pour Kaitai. * +* * +* Retour : Type prêt à emploi ou NULL si non trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiType *find_sub_type(const kaitai_scope_t *locals, const char *name) +{ + GKaitaiType *result; /* Instance à retourner */ + size_t i; /* Boucle de parcours */ + GKaitaiParser *parser; /* Lecteur d'origine */ + + GMatchRecord *list[] = { locals->last, locals->parent, locals->root }; + + result = NULL; + + for (i = 0; i < 3; i++) + { + if (list[i] == NULL) + continue; + + parser = g_match_record_get_creator(list[i]); + + if (G_IS_KAITAI_STRUCT(parser)) + result = g_kaitai_structure_find_sub_type(G_KAITAI_STRUCT(parser), name); + + g_object_unref(G_OBJECT(parser)); + + if (result != NULL) + break; + + } + + return result; + +} diff --git a/plugins/kaitai/scope.h b/plugins/kaitai/scope.h new file mode 100644 index 0000000..5dc52bf --- /dev/null +++ b/plugins/kaitai/scope.h @@ -0,0 +1,72 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scope.h - prototypes pour les recherches d'éléments de lecture + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef _PLUGINS_KAITAI_SCOPE_H +#define _PLUGINS_KAITAI_SCOPE_H + + +#include "record.h" +#include "parsers/meta.h" +#include "parsers/type.h" + + + +/* Accès aux différentes variables de contexte */ +typedef struct _kaitai_scope_t +{ + GKaitaiMeta *meta; /* Informations globales */ + + GMatchRecord *root; /* Variable "_root" */ + GMatchRecord *parent; /* Variable "_parent" */ + GMatchRecord *last; /* Variable "_" */ + +} kaitai_scope_t; + + +/* Initialise un contexte pour correspondances Kaitai établies. */ +void init_record_scope(kaitai_scope_t *, GKaitaiMeta *); + +/* Vide un contexte de correspondances Kaitai établies. */ +void reset_record_scope(kaitai_scope_t *); + +/* Copie un contexte de correspondances Kaitai établies. */ +void copy_record_scope(kaitai_scope_t *, const kaitai_scope_t *); + +/* Retourne le souvenir d'une correspondance racine. */ +GMatchRecord *get_root_record(const kaitai_scope_t *); + +/* Retourne le souvenir de la correspondance parente effectuée. */ +GMatchRecord *get_parent_record(const kaitai_scope_t *); + +/* Conserve le souvenir de la dernière correspondance effectuée. */ +void remember_last_record(kaitai_scope_t *, GMatchRecord *); + +/* Retourne le souvenir de la dernière correspondance effectuée. */ +GMatchRecord *get_last_record(const kaitai_scope_t *); + +/* Recherche la définition d'un type nouveau pour Kaitai. */ +GKaitaiType *find_sub_type(const kaitai_scope_t *, const char *); + + + +#endif /* _PLUGINS_KAITAI_SCOPE_H */ diff --git a/plugins/kaitai/stream-int.h b/plugins/kaitai/stream-int.h new file mode 100644 index 0000000..50b71df --- /dev/null +++ b/plugins/kaitai/stream-int.h @@ -0,0 +1,55 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * stream-int.h - prototypes pour les données associées à un flux de données Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_STREAM_INT_H +#define PLUGINS_KAITAI_STREAM_INT_H + + +#include "stream.h" + + + +/* Flux de données à disposition d'une analyse Kaitai (instance) */ +struct _GKaitaiStream +{ + GObject parent; /* A laisser en premier */ + + GBinContent *content; /* Contenu brut manipulé */ + vmpa2t pos; /* Tête de lecture dans le flux*/ + +}; + +/* Flux de données à disposition d'une analyse Kaitai (classe) */ +struct _GKaitaiStreamClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Met en place un flux de données pour Kaitai. */ +bool g_kaitai_stream_create(GKaitaiStream *, GBinContent *, const vmpa2t *); + + + +#endif /* PLUGINS_KAITAI_STREAM_INT_H */ diff --git a/plugins/kaitai/stream.c b/plugins/kaitai/stream.c new file mode 100644 index 0000000..66d0f8e --- /dev/null +++ b/plugins/kaitai/stream.c @@ -0,0 +1,237 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * stream.c - données associées à un flux de données Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "stream.h" + + +#include "stream-int.h" + + + +/* Initialise la classe des flux de données pour Kaitai. */ +static void g_kaitai_stream_class_init(GKaitaiStreamClass *); + +/* Initialise un flux de données accessibles à Kaitai. */ +static void g_kaitai_stream_init(GKaitaiStream *); + +/* Supprime toutes les références externes. */ +static void g_kaitai_stream_dispose(GKaitaiStream *); + +/* Procède à la libération totale de la mémoire. */ +static void g_kaitai_stream_finalize(GKaitaiStream *); + + + +/* Indique le type défini pour un flux de données manipulé par une lecture Kaitai. */ +G_DEFINE_TYPE(GKaitaiStream, g_kaitai_stream, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des flux de données pour Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_stream_class_init(GKaitaiStreamClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_stream_dispose; + object->finalize = (GObjectFinalizeFunc)g_kaitai_stream_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : stream = instance à initialiser. * +* * +* Description : Initialise un flux de données accessibles à Kaitai. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_stream_init(GKaitaiStream *stream) +{ + +} + + +/****************************************************************************** +* * +* Paramètres : stream = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_stream_dispose(GKaitaiStream *stream) +{ + G_OBJECT_CLASS(g_kaitai_stream_parent_class)->dispose(G_OBJECT(stream)); + +} + + +/****************************************************************************** +* * +* Paramètres : stream = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_kaitai_stream_finalize(GKaitaiStream *stream) +{ + G_OBJECT_CLASS(g_kaitai_stream_parent_class)->finalize(G_OBJECT(stream)); + +} + + +/****************************************************************************** +* * +* Paramètres : content = contenu binaire parcouru par une analyse Kaitai. * +* pos = tête de lecture courante. * +* * +* Description : Rassemble les éléments constituant un flux de données Kaitai.* +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GKaitaiStream *g_kaitai_stream_new(GBinContent *content, const vmpa2t *pos) +{ + GKaitaiStream *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_KAITAI_STREAM, NULL); + + if (!g_kaitai_stream_create(result, content, pos)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : attrib = lecteur d'attribut Kaitai à initialiser pleinement.* +* content = contenu binaire parcouru par une analyse Kaitai. * +* pos = tête de lecture courante. * +* * +* Description : Met en place un flux de données pour Kaitai. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_stream_create(GKaitaiStream *stream, GBinContent *content, const vmpa2t *pos) +{ + bool result; /* Bilan à retourner */ + + result = true; + + stream->content = content; + g_object_ref(G_OBJECT(content)); + + copy_vmpa(&stream->pos, pos); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : stream = flux de données Kaitai à consulter. * +* * +* Description : Indique le contenu de données binaires lié au flux Kaitai. * +* * +* Retour : Contenu binaire associé au flux de données. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GBinContent *g_kaitai_stream_get_content(const GKaitaiStream *stream) +{ + GBinContent *result; /* Instance à renvoyer */ + + result = stream->content; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : stream = flux de données Kaitai à consulter. * +* * +* Description : Détermine si la fin des données a été atteinte. * +* * +* Retour : true si la tête de lecture est en position finale, ou false. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_kaitai_stream_has_reached_eof(const GKaitaiStream *stream) +{ + bool result; /* Bilan à retourner */ + vmpa2t end; /* Position finale du flux */ + int ret; /* Bilan d'une comparaison */ + + g_binary_content_compute_end_pos(stream->content, &end); + + ret = cmp_vmpa_by_phy(&stream->pos, &end); + + result = (ret == 0); + + return result; + +} diff --git a/plugins/kaitai/stream.h b/plugins/kaitai/stream.h new file mode 100644 index 0000000..ee82c6d --- /dev/null +++ b/plugins/kaitai/stream.h @@ -0,0 +1,65 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * stream.h - prototypes pour les données associées à un flux de données Kaitai + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_KAITAI_STREAM_H +#define PLUGINS_KAITAI_STREAM_H + + +#include <glib-object.h> +#include <stdbool.h> + + +#include <analysis/content.h> + + + +#define G_TYPE_KAITAI_STREAM g_kaitai_stream_get_type() +#define G_KAITAI_STREAM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_STREAM, GKaitaiStream)) +#define G_IS_KAITAI_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_STREAM)) +#define G_KAITAI_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_STREAM, GKaitaiStreamClass)) +#define G_IS_KAITAI_STREAM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_STREAM)) +#define G_KAITAI_STREAM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_STREAM, GKaitaiStreamClass)) + + +/* Flux de données à disposition d'une analyse Kaitai (instance) */ +typedef struct _GKaitaiStream GKaitaiStream; + +/* Flux de données à disposition d'une analyse Kaitai (classe) */ +typedef struct _GKaitaiStreamClass GKaitaiStreamClass; + + +/* Indique le type défini pour un flux de données manipulé par une lecture Kaitai. */ +GType g_kaitai_stream_get_type(void); + +/* Rassemble les éléments constituant un flux de données Kaitai. */ +GKaitaiStream *g_kaitai_stream_new(GBinContent *, const vmpa2t *); + +/* Indique le contenu de données binaires lié au flux Kaitai. */ +GBinContent *g_kaitai_stream_get_content(const GKaitaiStream *); + +/* Détermine si la fin des données a été atteinte. */ +bool g_kaitai_stream_has_reached_eof(const GKaitaiStream *); + + + +#endif /* PLUGINS_KAITAI_STREAM_H */ diff --git a/plugins/kaitai/tokens.l b/plugins/kaitai/tokens.l new file mode 100644 index 0000000..8c93299 --- /dev/null +++ b/plugins/kaitai/tokens.l @@ -0,0 +1,329 @@ + +%top { + +#include <assert.h> +#include <malloc.h> +#include <string.h> + +#include <common/extstr.h> + +#include "grammar.h" + +} + + +%{ + +#define PUSH_STATE(s) yy_push_state(s, yyscanner) +#define POP_STATE yy_pop_state(yyscanner) + +%} + + +%option bison-bridge reentrant +%option stack +%option nounput + //%option noinput +%option noyywrap +%option noyy_top_state +%option yylineno +%option never-interactive + + +%x encoding +%x escaped_str +%x plain_str + + +%% + + +%{ + + /* no init C code */ + +%} + + +"+" { return PLUS; } +"-" { return MINUS; } +"*" { return MUL; } +"/" { return DIV; } +"%" { return MOD; } + +"<" { return LT; } +"<=" { return LE; } +"==" { return EQ; } +"!=" { return NE; } +">" { return GT; } +">=" { return GE; } + +"<<" { return SHIFT_LEFT; } +">>" { return SHIFT_RIGHT; } +"&" { return BIT_AND; } +"|" { return BIT_OR; } +"^" { return BIT_XOR; } + +"not" { return NOT; } +"and" { return AND; } +"or" { return OR; } + +"(" { return PAREN_O; } +")" { return PAREN_C; } +"[" { return HOOK_O; } +"]" { return HOOK_C; } +"," { return COMMA; } +"." { return DOT; } + +"?" { return QMARK; } +":" { return COLON; } +"::" { return DOUBLE_COLON; } + +".size" { return METH_SIZE; } +".length" { return METH_LENGTH; } +".reverse" { return METH_REVERSE; } +".substring" { return METH_SUBSTRING; } +".to_i" { return METH_TO_I; } +".to_i(" { return METH_TO_I_RAD; } +".to_s" { return METH_TO_S; } +".to_s(" { PUSH_STATE(encoding); return METH_TO_S_ENC; } + +"_root" { return ROOT; } +"_parent" { return PARENT; } +"_" { return LAST; } +"_io" { return IO; } +"._io" { return METH_IO; } +".eof" { return IO_EOF; } + +"true" { return TRUE_CONST; } +"false" { return FALSE_CONST; } + + +%{ /* Lecteurs de valeurs entières */ %} + +0[bB][01]+ { + char *__end; + yylval->unsigned_integer = strtoull(yytext + 2, &__end, 2); + if (__end != (yytext + yyleng)) + YY_FATAL_ERROR("failed to parse integer"); + return UNSIGNED_INTEGER; + } + +0[bB][01]{1,4}(_[01]{4})+ { + char *__tmp; + char *__end; + __tmp = strdup(yytext); + __tmp = strrpl(__tmp, "_", ""); + yylval->unsigned_integer = strtoull(__tmp + 2, &__end, 2); + if (__end != (__tmp + strlen(__tmp))) + { + free(__tmp); + YY_FATAL_ERROR("failed to parse integer"); + } + else free(__tmp); + return UNSIGNED_INTEGER; + } + +(0|[1-9][0-9]*) { + char *__end; + yylval->unsigned_integer = strtoull(yytext, &__end, 10); + if (__end != (yytext + yyleng)) + YY_FATAL_ERROR("failed to parse integer"); + return UNSIGNED_INTEGER; + } + +[1-9][0-9]{0,2}(_[1-9][0-9]{2})+ { + char *__tmp; + char *__end; + __tmp = strdup(yytext); + __tmp = strrpl(__tmp, "_", ""); + yylval->unsigned_integer = strtoull(__tmp, &__end, 10); + if (__end != (__tmp + strlen(__tmp))) + { + free(__tmp); + YY_FATAL_ERROR("failed to parse integer"); + } + else free(__tmp); + return UNSIGNED_INTEGER; + } + +-(0|[1-9][0-9]*) { + char *__end; + yylval->signed_integer = strtoll(yytext, &__end, 10); + if (__end != (yytext + yyleng)) + YY_FATAL_ERROR("failed to parse integer"); + return SIGNED_INTEGER; + } + +-[1-9][0-9]{0,2}(_[1-9][0-9]{2})+ { + char *__tmp; + char *__end; + __tmp = strdup(yytext); + __tmp = strrpl(__tmp, "_", ""); + yylval->signed_integer = strtoll(__tmp, &__end, 10); + if (__end != (__tmp + strlen(__tmp))) + { + free(__tmp); + YY_FATAL_ERROR("failed to parse integer"); + } + else free(__tmp); + return SIGNED_INTEGER; + } + +0[xX][0-9a-fA-F]+ { + char *__end; + yylval->unsigned_integer = strtoull(yytext, &__end, 16); + if (__end != (yytext + yyleng)) + YY_FATAL_ERROR("failed to parse integer"); + return UNSIGNED_INTEGER; + } + +0[xX][0-9a-fA-F]{1,4}(_[0-9a-fA-F]{4})+ { + char *__tmp; + char *__end; + __tmp = strdup(yytext); + __tmp = strrpl(__tmp, "_", ""); + yylval->unsigned_integer = strtoull(__tmp, &__end, 16); + if (__end != (__tmp + strlen(__tmp))) + { + free(__tmp); + YY_FATAL_ERROR("failed to parse integer"); + } + else free(__tmp); + return UNSIGNED_INTEGER; + } + + + +-?(0|[1-9][0-9]*\.[0-9]+) { + char *__end; + yylval->floating_number = strtod(yytext, &__end); + if (__end != (yytext + yyleng)) + YY_FATAL_ERROR("failed to parse float"); + return FLOAT; + } + + +%{ /* Paramètre d'encodage */ %} + +<encoding>["'][-_A-Za-z0-9 ]+["'] { + yylval->sized_cstring.data = yytext + 1; + yylval->sized_cstring.len = yyleng - 2; + return ENCODING_NAME; + } + +<encoding>")" { POP_STATE; return PAREN_C; } + + +[a-z][a-z0-9_]* { + yylval->sized_cstring.data = yytext; + yylval->sized_cstring.len = yyleng; + return IDENTIFIER; + } + +[^\\\[\],"'()\.: ]+ { + yylval->sized_cstring.data = yytext; + yylval->sized_cstring.len = yyleng; + return PLAIN_BYTES; + } + + +%{ /* Lecteurs des tableaux de définition d'octets */ %} + +"\"" { PUSH_STATE(escaped_str); } + + +<escaped_str>[^\\"]+ { + yylval->sized_cstring.data = yytext; + yylval->sized_cstring.len = yyleng; + return RAW_BYTES; + } + +<escaped_str>"\\a" { yylval->byte = '\a'; return RAW_BYTE; } +<escaped_str>"\\b" { yylval->byte = '\b'; return RAW_BYTE; } +<escaped_str>"\\t" { yylval->byte = '\t'; return RAW_BYTE; } +<escaped_str>"\\n" { yylval->byte = '\n'; return RAW_BYTE; } +<escaped_str>"\\v" { yylval->byte = '\v'; return RAW_BYTE; } +<escaped_str>"\\f" { yylval->byte = '\f'; return RAW_BYTE; } +<escaped_str>"\\r" { yylval->byte = '\r'; return RAW_BYTE; } +<escaped_str>"\\e" { yylval->byte = '\e'; return RAW_BYTE; } +<escaped_str>"\\\"" { yylval->byte = '"'; return RAW_BYTE; } +<escaped_str>"\\'" { yylval->byte = '\''; return RAW_BYTE; } +<escaped_str>"\\\\" { yylval->byte = '\\'; return RAW_BYTE; } +<escaped_str>"\\0" { yylval->byte = '\0'; return RAW_BYTE; } + +<escaped_str>\\[0-9]{1,3} { + char __tmp[4]; + memcpy(__tmp, yytext + 1, yyleng - 1); + __tmp[yyleng] = '\0'; + yylval->byte = strtoull(__tmp, NULL, 8); + return RAW_BYTE; + } + +<escaped_str>"\"" { POP_STATE; } + + + + +"'" { PUSH_STATE(plain_str); } + +<plain_str>[^']+ { + yylval->sized_cstring.data = yytext; + yylval->sized_cstring.len = yyleng; + return PLAIN_BYTES; + } + +<plain_str>['] { POP_STATE; } + +[.]$ { +#ifndef NDEBUG + int ch; +#endif + yylval->sized_cstring.data = yytext; + yylval->sized_cstring.len = yyleng; +#ifndef NDEBUG + ch = input(yyscanner); + assert(ch == '\n'); +#else + input(yyscanner); +#endif + return RAW_BYTES_WITH_ENDING_DOT; + } + +[^\\\[\],"'()\.: ]+[.]$ { +#ifndef NDEBUG + int ch; +#endif + yylval->sized_cstring.data = yytext; + yylval->sized_cstring.len = yyleng; +#ifndef NDEBUG + ch = input(yyscanner); + assert(ch == '\n'); +#else + input(yyscanner); +#endif + return RAW_BYTES_WITH_ENDING_DOT; + } + + +%{ /* Actions par défaut */ %} + +<*>[ \t\n]+ { } + +<*>. { + char *msg; + int ret; + ret = asprintf(&msg, + "Unhandled token in rule definition: '%s'", + yytext); + if (ret == -1) + YY_FATAL_ERROR("Unhandled token in undisclosed rule definition"); + else + { + YY_FATAL_ERROR(msg); + free(msg); + } + } + + +%% diff --git a/plugins/libcsem/Makefile.am b/plugins/libcsem/Makefile.am index c55a2f8..a7a264f 100644 --- a/plugins/libcsem/Makefile.am +++ b/plugins/libcsem/Makefile.am @@ -15,10 +15,12 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN' endif -liblibcsem_la_SOURCES = \ - exit.h exit.c \ +liblibcsem_la_SOURCES = \ + exit.h exit.c \ semantic.h semantic.c +liblibcsem_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + liblibcsem_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -29,8 +31,3 @@ liblibcsem_la_LDFLAGS = \ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(liblibcsem_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/lnxsyscalls/Makefile.am b/plugins/lnxsyscalls/Makefile.am index 9c5158f..21feaa5 100644 --- a/plugins/lnxsyscalls/Makefile.am +++ b/plugins/lnxsyscalls/Makefile.am @@ -14,17 +14,17 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN' endif -liblnxsyscalls_la_SOURCES = \ - collect.h collect.c \ - core.h core.c \ - db.h db.c \ - hops.h \ - hops_armv7.h hops_armv7.c \ - hunter.h hunter.c \ - syscall.h syscall.c \ +liblnxsyscalls_la_SOURCES = \ + collect.h collect.c \ + core.h core.c \ + db.h db.c \ + hops.h \ + hops_armv7.h hops_armv7.c \ + hunter.h hunter.c \ + syscall.h syscall.c \ writer.h writer.c -liblnxsyscalls_la_LIBADD = +liblnxsyscalls_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src liblnxsyscalls_la_LDFLAGS = \ -avoid-version \ @@ -44,10 +44,3 @@ dbdir = $(pluginsdatadir) devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(liblnxsyscalls_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/lnxsyscalls/hunter.h b/plugins/lnxsyscalls/hunter.h index ed191f4..c2040eb 100644 --- a/plugins/lnxsyscalls/hunter.h +++ b/plugins/lnxsyscalls/hunter.h @@ -26,7 +26,7 @@ #include <analysis/binary.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> #include "hops.h" diff --git a/plugins/mobicore/Makefile.am b/plugins/mobicore/Makefile.am index 761108e..e8616c2 100644 --- a/plugins/mobicore/Makefile.am +++ b/plugins/mobicore/Makefile.am @@ -11,13 +11,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/../chrysalide-libs' endif -libmobicore_la_SOURCES = \ - core.h core.c \ - mclf-def.h \ - mclf-int.h mclf-int.c \ - mclf.h mclf.c \ +libmobicore_la_SOURCES = \ + core.h core.c \ + mclf-def.h \ + mclf-int.h mclf-int.c \ + mclf.h mclf.c \ symbols.h symbols.c +libmobicore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libmobicore_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -27,8 +29,3 @@ libmobicore_la_LDFLAGS = \ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libmobicore_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pe/Makefile.am b/plugins/pe/Makefile.am index 038b8c5..e9cd482 100644 --- a/plugins/pe/Makefile.am +++ b/plugins/pe/Makefile.am @@ -37,19 +37,21 @@ PYTHON3_SUBDIRS = python endif -libpe_la_SOURCES = \ - core.h core.c \ - pe-int.h pe-int.c \ - format.h format.c \ - pe_def.h \ - rich.h rich.c \ - routine.h routine.c \ - section.h section.c \ +libpe_la_SOURCES = \ + core.h core.c \ + pe-int.h pe-int.c \ + format.h format.c \ + pe_def.h \ + rich.h rich.c \ + routine.h routine.c \ + section.h section.c \ symbols.h symbols.c -libpe_la_LIBADD = \ +libpe_la_LIBADD = \ $(PYTHON3_LIBADD) +libpe_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libpe_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -61,8 +63,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpe_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/pe/core.c b/plugins/pe/core.c index aa51c18..ddbacf5 100644 --- a/plugins/pe/core.c +++ b/plugins/pe/core.c @@ -24,18 +24,17 @@ #include "core.h" -#include <config.h> #include <core/global.h> #include <plugins/self.h> #include "format.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -65,7 +64,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS result = add_format_pe_module_to_python_module(); #else result = true; diff --git a/plugins/pe/python/Makefile.am b/plugins/pe/python/Makefile.am index 18634a3..5949821 100644 --- a/plugins/pe/python/Makefile.am +++ b/plugins/pe/python/Makefile.am @@ -1,23 +1,17 @@ noinst_LTLIBRARIES = libpepython.la -libpepython_la_SOURCES = \ - constants.h constants.c \ - format.h format.c \ - module.h module.c \ - routine.h routine.c \ +libpepython_la_SOURCES = \ + constants.h constants.c \ + format.h format.c \ + module.h module.c \ + routine.h routine.c \ translate.h translate.c - -libpepython_la_LDFLAGS = +libpepython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpepython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pe/python/format.c b/plugins/pe/python/format.c index d295da4..4bbb99a 100644 --- a/plugins/pe/python/format.c +++ b/plugins/pe/python/format.c @@ -115,7 +115,7 @@ static PyObject *py_pe_format_new(PyTypeObject *type, PyObject *args, PyObject * if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -539,7 +539,10 @@ bool register_python_pe_format(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PE_FORMAT, type, get_python_executable_format_type())) + if (!ensure_python_executable_format_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_PE_FORMAT, type)) return false; if (!define_python_pe_format_constants(type)) diff --git a/plugins/pe/python/routine.c b/plugins/pe/python/routine.c index cebeb2a..fd30e6d 100644 --- a/plugins/pe/python/routine.c +++ b/plugins/pe/python/routine.c @@ -221,7 +221,9 @@ bool register_python_pe_exported_routine(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PE_EXPORTED_ROUTINE, type, get_python_binary_routine_type())) + /* TODO : ensure get_python_binary_routine_type() */ + + if (!register_class_for_pygobject(dict, G_TYPE_PE_EXPORTED_ROUTINE, type)) return false; if (!define_python_pe_exported_routine_constants(type)) @@ -461,7 +463,9 @@ bool register_python_pe_imported_routine(PyObject *module) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PE_IMPORTED_ROUTINE, type, get_python_pe_exported_routine_type())) + /* TODO : ensure get_python_pe_exported_routine_type() */ + + if (!register_class_for_pygobject(dict, G_TYPE_PE_IMPORTED_ROUTINE, type)) return false; return true; diff --git a/plugins/pe/symbols.h b/plugins/pe/symbols.h index bb260cd..5c4b796 100644 --- a/plugins/pe/symbols.h +++ b/plugins/pe/symbols.h @@ -29,7 +29,7 @@ #include <glibext/delayed.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> diff --git a/plugins/pychrysalide/Makefile.am b/plugins/pychrysalide/Makefile.am index fb3986c..4b6e551 100644 --- a/plugins/pychrysalide/Makefile.am +++ b/plugins/pychrysalide/Makefile.am @@ -13,32 +13,52 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN/chrysalide-libs' endif -pychrysalide_la_SOURCES = \ - access.h access.c \ - core.h core.c \ - helpers.h helpers.c \ - star.h star.c \ - strenum.h strenum.c \ - struct.h struct.c \ - weak.h weak.c - -pychrysalide_la_LIBADD = \ - analysis/libpychrysaanalysis.la \ - arch/libpychrysaarch.la \ - common/libpychrysacommon.la \ - core/libpychrysacore.la \ - debug/libpychrysadebug.la \ - format/libpychrysaformat.la \ - glibext/libpychrysaglibext.la \ - gtkext/libpychrysagtkext.la \ - gui/libpychrysagui.la \ - mangling/libpychrysamangling.la \ +if BUILD_GTK_SUPPORT + +GTKEXT_LIBADD = \ + gtkext/libpychrysagtkext.la + +GTKEXT_SUBDIR = \ + gtkext + +GUI_LIBADD = \ + gui/libpychrysagui.la + +GUI_SUBDIR = \ + gui + +endif + + +pychrysalide_la_SOURCES = \ + access.h access.c \ + core.h core.c \ + helpers.h helpers.c \ + star.h star.c \ + strenum.h strenum.c \ + struct.h struct.c + +AM_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + +pychrysalide_la_LIBADD = \ + analysis/libpychrysaanalysis.la \ + arch/libpychrysaarch.la \ + common/libpychrysacommon.la \ + core/libpychrysacore.la \ + debug/libpychrysadebug.la \ + format/libpychrysaformat.la \ + glibext/libpychrysaglibext.la \ + $(GTKEXT_LIBADD) \ + $(GUI_LIBADD) \ + mangling/libpychrysamangling.la \ plugins/libpychrysaplugins.la # -ldl: dladdr(), dlerror() pychrysalide_la_LDFLAGS = \ -module -avoid-version -ldl \ - $(LIBPYTHON_LIBS) $(LIBPYGOBJECT_LIBS) \ + $(LIBPYTHON_INTERPRETER_LIBS) \ + $(LIBPYGOBJECT_LIBS) \ -L$(top_srcdir)/src/.libs -lchrysacore \ $(RUN_PATH) @@ -48,9 +68,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(pychrysalide_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = analysis arch common core debug format glibext gtkext gui mangling plugins +SUBDIRS = analysis arch common core debug format glibext $(GTKEXT_SUBDIR) $(GUI_SUBDIR) mangling plugins diff --git a/plugins/pychrysalide/analysis/Makefile.am b/plugins/pychrysalide/analysis/Makefile.am index d09cced..43e8ed2 100644 --- a/plugins/pychrysalide/analysis/Makefile.am +++ b/plugins/pychrysalide/analysis/Makefile.am @@ -1,28 +1,30 @@ noinst_LTLIBRARIES = libpychrysaanalysis.la -libpychrysaanalysis_la_SOURCES = \ - binary.h binary.c \ - block.h block.c \ - cattribs.h cattribs.c \ - constants.h constants.c \ - content.h content.c \ - loaded.h loaded.c \ - loading.h loading.c \ - module.h module.c \ - project.h project.c \ - routine.h routine.c \ - type.h type.c \ +libpychrysaanalysis_la_SOURCES = \ + binary.h binary.c \ + block.h block.c \ + cattribs.h cattribs.c \ + constants.h constants.c \ + content.h content.c \ + loaded.h loaded.c \ + loading.h loading.c \ + module.h module.c \ + project.h project.c \ + routine.h routine.c \ + type.h type.c \ variable.h variable.c libpychrysaanalysis_la_LIBADD = \ contents/libpychrysaanalysiscontents.la \ db/libpychrysaanalysisdb.la \ disass/libpychrysaanalysisdisass.la \ + scan/libpychrysaanalysisscan.la \ storage/libpychrysaanalysisstorage.la \ types/libpychrysaanalysistypes.la -libpychrysaanalysis_la_LDFLAGS = +libpychrysaanalysis_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -30,9 +32,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysis_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = contents db disass storage types +SUBDIRS = contents db disass scan storage types diff --git a/plugins/pychrysalide/analysis/binary.c b/plugins/pychrysalide/analysis/binary.c index 2f8af5f..6599ecc 100644 --- a/plugins/pychrysalide/analysis/binary.c +++ b/plugins/pychrysalide/analysis/binary.c @@ -124,27 +124,23 @@ static PyObject *py_loaded_binary_new(PyTypeObject *type, PyObject *args, PyObje static PyObject *py_loaded_binary_get_client(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ - int internal; /* Nature du client visé */ - int ret; /* Bilan de lecture des args. */ GLoadedBinary *binary; /* Binaire en cours d'analyse */ - GHubClient *client; /* Eventuel client en place */ + GAnalystClient *client; /* Eventuel client en place */ #define LOADED_BINARY_GET_CLIENT_METHOD PYTHON_METHOD_DEF \ ( \ - get_client, "$self, /, internal=True", \ - METH_VARARGS, py_loaded_binary, \ + get_client, "$self", \ + METH_NOARGS, py_loaded_binary, \ "Provide the client connected to an internal or remote server" \ " if defined, or return None otherwise.\n" \ + "\n" \ + "The returned object is a pychrysalide.analysis.db.AnalystClient" \ + " instance or *None*." \ ) - internal = 1; - - ret = PyArg_ParseTuple(args, "|p", &internal); - if (!ret) return NULL; - binary = G_LOADED_BINARY(pygobject_get(self)); - client = g_loaded_binary_get_client(binary, internal); + client = g_loaded_binary_get_client(binary); if (client != NULL) { @@ -566,7 +562,7 @@ bool ensure_python_loaded_binary_is_registered(void) if (!ensure_python_loaded_content_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_LOADED_BINARY, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_LOADED_BINARY, type)) return false; } diff --git a/plugins/pychrysalide/analysis/block.c b/plugins/pychrysalide/analysis/block.c index 0b09eb7..7f74c2f 100644 --- a/plugins/pychrysalide/analysis/block.c +++ b/plugins/pychrysalide/analysis/block.c @@ -353,7 +353,7 @@ bool ensure_python_code_block_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CODE_BLOCK, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CODE_BLOCK, type)) return false; } @@ -612,7 +612,7 @@ bool ensure_python_block_list_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BLOCK_LIST, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BLOCK_LIST, type)) return false; } diff --git a/plugins/pychrysalide/analysis/cattribs.c b/plugins/pychrysalide/analysis/cattribs.c index be5c5b1..84a5e1d 100644 --- a/plugins/pychrysalide/analysis/cattribs.c +++ b/plugins/pychrysalide/analysis/cattribs.c @@ -45,9 +45,6 @@ static PyObject *py_content_attributes_new(PyTypeObject *, PyObject *, PyObject /* Fournit l'ensemble des clefs d'un ensemble d'attributs. */ static PyObject *py_content_attributes_subscript(PyObject *, PyObject *); -/* Fournit le fichier de base compris dans le chemin initial. */ -static PyObject *py_content_attributes_get_filename(PyObject *, void *); - /* Fournit l'ensemble des clefs d'un ensemble d'attributs. */ static PyObject *py_content_attributes_get_keys(PyObject *, void *); @@ -72,7 +69,10 @@ static PyObject *py_content_attributes_new(PyTypeObject *type, PyObject *args, P PyObject *result; /* Instance à retourner */ const char *path; /* Chemin d'accès à traiter */ int ret; /* Bilan de lecture des args. */ + char *filename; /* Nom de fichier embarqué */ GContentAttributes *attribs; /* Création GLib à transmettre */ + PyObject *obj; /* Objet Python à retourner */ + PyObject *str; /* Chaîne à retourner */ #define CONTENT_ATTRIBUTES_DOC \ "ContentAttributes is a set of values used at binary content loading.\n" \ @@ -87,25 +87,43 @@ static PyObject *py_content_attributes_new(PyTypeObject *type, PyObject *args, P "\n" \ " ContentAttributes(path)\n" \ "\n" \ - "Where path is a list of parameters: '[...]&key0=value0&key1=value1...'" + "Where path is a list of parameters: '[...]&key0=value0&key1=value1...'" \ + "\n" \ + "The constructor returns a tuple containing a ContentAttributes instance" \ + " and the original targot filename." ret = PyArg_ParseTuple(args, "s", &path); if (!ret) return NULL; - attribs = g_content_attributes_new(path); + attribs = g_content_attributes_new(path, &filename); if (attribs != NULL) { g_object_ref_sink(G_OBJECT(attribs)); - result = pygobject_new(G_OBJECT(attribs)); + obj = pygobject_new(G_OBJECT(attribs)); g_object_unref(attribs); } else { - result = Py_None; - Py_INCREF(result); + obj = Py_None; + Py_INCREF(obj); } + if (filename != NULL) + { + str = PyUnicode_FromString(filename); + free(filename); + } + else + { + str = Py_None; + Py_INCREF(str); + } + + result = PyTuple_New(2); + PyTuple_SetItem(result, 0, obj); + PyTuple_SetItem(result, 1, str); + return result; } @@ -200,50 +218,6 @@ static PyObject *py_content_attributes_get_keys(PyObject *self, void *closure) /****************************************************************************** * * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit le fichier de base compris dans le chemin initial. * -* * -* Retour : Nom de fichier renvoyant vers un contenu à charger ou None. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_content_attributes_get_filename(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GContentAttributes *cattribs; /* Version native */ - const char *filename; /* Nom de fichier natif */ - -#define CONTENT_ATTRIBUTES_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - filename, py_content_attributes, \ - "Filename extracted from the path provided to the attribute set," \ - " constructor, or None if no filename was defined." \ -) - - cattribs = G_CONTENT_ATTRIBUTES(pygobject_get(self)); - - filename = g_content_attributes_get_filename(cattribs); - - if (filename != NULL) - result = PyUnicode_FromString(filename); - - else - { - result = Py_None; - Py_INCREF(result); - } - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -267,7 +241,6 @@ PyTypeObject *get_python_content_attributes_type(void) }; static PyGetSetDef py_content_attributes_getseters[] = { - CONTENT_ATTRIBUTES_FILENAME_ATTRIB, CONTENT_ATTRIBUTES_KEYS_ATTRIB, { NULL } }; @@ -321,7 +294,7 @@ bool ensure_python_content_attributes_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_ATTRIBUTES, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_ATTRIBUTES, type)) return false; } diff --git a/plugins/pychrysalide/analysis/content.c b/plugins/pychrysalide/analysis/content.c index 68ecba2..c30cdd8 100644 --- a/plugins/pychrysalide/analysis/content.c +++ b/plugins/pychrysalide/analysis/content.c @@ -40,6 +40,7 @@ #include "cattribs.h" #include "constants.h" +#include "storage/serialize.h" #include "../access.h" #include "../helpers.h" #include "../arch/vmpa.h" @@ -49,8 +50,13 @@ /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Procède à l'initialisation de l'interface de génération. */ -static void py_binary_content_interface_init(GBinContentIface *, gpointer *); +/* Initialise la classe générique des contenus de binaire. */ +static void py_binary_content_init_gclass(GBinContentClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(binary_content, G_TYPE_BIN_CONTENT, py_binary_content_init_gclass); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_binary_content_init(PyObject *, PyObject *, PyObject *); /* Fournit le nom associé au contenu binaire. */ static char *py_binary_content_describe_wrapper(const GBinContent *, bool); @@ -99,6 +105,9 @@ static int py_binary_content_set_attributes(PyObject *, PyObject *, void *); /* Fournit l'ensemble des attributs associés à un contenu. */ static PyObject *py_binary_content_get_attributes(PyObject *, void *); +/* Donne l'origine d'un contenu binaire. */ +static PyObject *py_binary_content_get_root(PyObject *, void *); + /* Fournit une empreinte unique (SHA256) pour les données. */ static PyObject *py_binary_content_get_checksum(PyObject *, void *); @@ -123,10 +132,10 @@ static PyObject *py_binary_content_get_data(PyObject *, void *); /****************************************************************************** * * -* Paramètres : iface = interface GLib à initialiser. * -* unused = adresse non utilisée ici. * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * * * -* Description : Procède à l'initialisation de l'interface de génération. * +* Description : Initialise la classe générique des contenus de binaire. * * * * Retour : - * * * @@ -134,21 +143,45 @@ static PyObject *py_binary_content_get_data(PyObject *, void *); * * ******************************************************************************/ -static void py_binary_content_interface_init(GBinContentIface *iface, gpointer *unused) +static void py_binary_content_init_gclass(GBinContentClass *class, gpointer unused) +{ + class->describe = py_binary_content_describe_wrapper; + + class->read_raw = py_binary_content_read_raw_wrapper; + class->read_u8 = py_binary_content_read_u8_wrapper; + class->read_u16 = py_binary_content_read_u16_wrapper; + class->read_u32 = py_binary_content_read_u32_wrapper; + class->read_u64 = py_binary_content_read_u64_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_binary_content_init(PyObject *self, PyObject *args, PyObject *kwds) { + int ret; /* Bilan de lecture des args. */ + #define BINARY_CONTENT_DOC \ - "The BinContent is an interface which handles access to a given binary" \ - " content.\n" \ + "A BinContent is an abstract object which handles access to a given" \ + " binary content.\n" \ "\n" \ "All of its implementations are located in the" \ " pychrysalide.analysis.contents module. The main implemantation is" \ " the pychrysalide.analysis.contents.FileContent class.\n" \ "\n" \ - "A typical class declaration for a new implementation looks like:\n" \ - "\n" \ - " class NewImplem(GObject.Object, BinContent):\n" \ - " ...\n" \ - "\n" \ "The following methods have to be defined for new implementations:\n" \ "* pychrysalide.analysis.BinContent._describe();\n" \ "* pychrysalide.analysis.BinContent._read_raw();\n" \ @@ -158,13 +191,12 @@ static void py_binary_content_interface_init(GBinContentIface *iface, gpointer * "* pychrysalide.analysis.BinContent._read_u32();\n" \ "* pychrysalide.analysis.BinContent._read_u64();\n" - iface->describe = py_binary_content_describe_wrapper; + /* Initialisation d'un objet GLib */ - iface->read_raw = py_binary_content_read_raw_wrapper; - iface->read_u8 = py_binary_content_read_u8_wrapper; - iface->read_u16 = py_binary_content_read_u16_wrapper; - iface->read_u32 = py_binary_content_read_u32_wrapper; - iface->read_u64 = py_binary_content_read_u64_wrapper; + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; } @@ -1133,6 +1165,48 @@ static PyObject *py_binary_content_get_attributes(PyObject *self, void *closure) * Paramètres : self = contenu binaire à manipuler. * * closure = adresse non utilisée ici. * * * +* Description : Donne l'origine d'un contenu binaire. * +* * +* Retour : Contenu à l'origine du contenu courant. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_binary_content_get_root(PyObject *self, void *closure) +{ + PyObject *result; /* Instance à retourner */ + GBinContent *content; /* Version GLib du format */ + GContentAttributes *attribs; /* Attributs à transmettre */ + +#define BINARY_CONTENT_ROOT_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + root, py_binary_content, \ + "Provide, as a pychrysalide.analysis.BinContent instance, the root" \ + " content leading to the current content." \ + "\n" \ + "This property is relevant only for" \ + " pychrysalide.analysis.contents.EncapsulatedContent objects." \ +) + + content = G_BIN_CONTENT(pygobject_get(self)); + + attribs = g_binary_content_get_attributes(content); + + result = pygobject_new(G_OBJECT(attribs)); + + g_object_unref(attribs); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = contenu binaire à manipuler. * +* closure = adresse non utilisée ici. * +* * * Description : Fournit une empreinte unique (SHA256) pour les données. * * * * Retour : Bilan de l'opération. * @@ -1347,6 +1421,7 @@ PyTypeObject *get_python_binary_content_type(void) static PyGetSetDef py_binary_content_getseters[] = { BINARY_CONTENT_ATTRIBUTES_ATTRIB, + BINARY_CONTENT_ROOT_ATTRIB, BINARY_CONTENT_CHECKSUM_ATTRIB, BINARY_CONTENT_SIZE_ATTRIB, BINARY_CONTENT_START_POS_ATTRIB, @@ -1360,14 +1435,17 @@ PyTypeObject *get_python_binary_content_type(void) PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.analysis.BinContent", - .tp_basicsize = sizeof(PyObject), + .tp_basicsize = sizeof(PyGObject), .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, .tp_doc = BINARY_CONTENT_DOC, .tp_methods = py_binary_content_methods, - .tp_getset = py_binary_content_getseters + .tp_getset = py_binary_content_getseters, + + .tp_init = py_binary_content_init, + .tp_new = py_binary_content_new, }; @@ -1394,23 +1472,18 @@ bool ensure_python_binary_content_is_registered(void) PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - static GInterfaceInfo info = { /* Paramètres d'inscription */ - - .interface_init = (GInterfaceInitFunc)py_binary_content_interface_init, - .interface_finalize = NULL, - .interface_data = NULL, - - }; - type = get_python_binary_content_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { + if (!ensure_python_serializable_object_is_registered()) + return false; + module = get_access_to_python_module("pychrysalide.analysis"); dict = PyModule_GetDict(module); - if (!register_interface_for_pygobject(dict, G_TYPE_BIN_CONTENT, type, &info)) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_CONTENT, type)) return false; if (!define_analysis_content_constants(type)) diff --git a/plugins/pychrysalide/analysis/contents/Makefile.am b/plugins/pychrysalide/analysis/contents/Makefile.am index 07fafd0..9238a58 100644 --- a/plugins/pychrysalide/analysis/contents/Makefile.am +++ b/plugins/pychrysalide/analysis/contents/Makefile.am @@ -1,22 +1,17 @@ noinst_LTLIBRARIES = libpychrysaanalysiscontents.la -libpychrysaanalysiscontents_la_SOURCES = \ - encapsulated.h encapsulated.c \ - file.h file.c \ - memory.h memory.c \ - module.h module.c \ +libpychrysaanalysiscontents_la_SOURCES = \ + encapsulated.h encapsulated.c \ + file.h file.c \ + memory.h memory.c \ + module.h module.c \ restricted.h restricted.c -libpychrysaanalysiscontents_la_LDFLAGS = +libpychrysaanalysiscontents_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysiscontents_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/analysis/contents/encapsulated.c b/plugins/pychrysalide/analysis/contents/encapsulated.c index ef26caa..e9583e6 100644 --- a/plugins/pychrysalide/analysis/contents/encapsulated.c +++ b/plugins/pychrysalide/analysis/contents/encapsulated.c @@ -28,7 +28,8 @@ #include <pygobject.h> -#include <analysis/contents/encapsulated.h> +#include <i18n.h> +#include <analysis/contents/encapsulated-int.h> #include "../content.h" @@ -37,8 +38,10 @@ -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_encaps_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(encaps_content, G_TYPE_ENCAPS_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_encaps_content_init(PyObject *, PyObject *, PyObject *); /* Indique la base d'un contenu binaire encapsulé. */ static PyObject *py_encaps_content_get_base(PyObject *, void *); @@ -53,26 +56,25 @@ static PyObject *py_encaps_content_get_endpoint(PyObject *, void *); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_encaps_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_encaps_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ GBinContent *base; /* Base de l'extraction */ const char *path; /* Chemin vers le contenu final*/ GBinContent *endpoint; /* Contenu accessible au final */ int ret; /* Bilan de lecture des args. */ - GBinContent *content; /* Version GLib du contenu */ + GEncapsContent *content; /* Version GLib du contenu */ #define ENCAPS_CONTENT_DOC \ "EncapsulatedContent gathers items relative to a binary encapsulated" \ @@ -93,20 +95,30 @@ static PyObject *py_encaps_content_new(PyTypeObject *type, PyObject *args, PyObj " pychrysalide.analysis.BinContent instances and the access path must" \ " be provided as a string." + /* Récupération des paramètres */ + ret = PyArg_ParseTuple(args, "O&sO&", convert_to_binary_content, &base, &path, convert_to_binary_content, &endpoint); - if (!ret) return NULL; + if (!ret) return -1; - content = g_encaps_content_new(base, path, endpoint); + /* Initialisation d'un objet GLib */ - result = pygobject_new(G_OBJECT(content)); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - if (content != NULL) - g_object_unref(content); + /* Eléments de base */ - return result; + content = G_ENCAPS_CONTENT(pygobject_get(self)); + + if (!g_encaps_content_create(content, base, path, endpoint)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create encapsulated content.")); + return -1; + } + + return 0; } @@ -275,7 +287,9 @@ PyTypeObject *get_python_encaps_content_type(void) .tp_methods = py_encaps_content_methods, .tp_getset = py_encaps_content_getseters, - .tp_new = py_encaps_content_new + + .tp_init = py_encaps_content_init, + .tp_new = py_encaps_content_new, }; @@ -310,7 +324,10 @@ bool ensure_python_encaps_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ENCAPS_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_binary_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ENCAPS_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/contents/file.c b/plugins/pychrysalide/analysis/contents/file.c index 93a1ce8..5bef069 100644 --- a/plugins/pychrysalide/analysis/contents/file.c +++ b/plugins/pychrysalide/analysis/contents/file.c @@ -28,16 +28,20 @@ #include <pygobject.h> -#include <analysis/contents/file.h> +#include <i18n.h> +#include <analysis/contents/file-int.h> +#include "memory.h" #include "../../access.h" #include "../../helpers.h" -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_file_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(file_content, G_TYPE_FILE_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_file_content_init(PyObject *, PyObject *, PyObject *); /* Fournit le nom de fichier associé au contenu binaire. */ static PyObject *py_file_content_get_filename(PyObject *, void *); @@ -46,24 +50,23 @@ static PyObject *py_file_content_get_filename(PyObject *, void *); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_file_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_file_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ const char *filename; /* Nom du fichier à charger */ int ret; /* Bilan de lecture des args. */ - GBinContent *content; /* Version GLib du contenu */ + GFileContent *content; /* Version GLib du contenu */ #define FILE_CONTENT_DOC \ "FileContent handles binary content loaded from a file.\n" \ @@ -74,17 +77,27 @@ static PyObject *py_file_content_new(PyTypeObject *type, PyObject *args, PyObjec "\n" \ "Where filename is a path to an existing file." + /* Récupération des paramètres */ + ret = PyArg_ParseTuple(args, "s", &filename); - if (!ret) return NULL; + if (!ret) return -1; - content = g_file_content_new(filename); + /* Initialisation d'un objet GLib */ - result = pygobject_new(G_OBJECT(content)); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - if (content != NULL) - g_object_unref(content); + /* Eléments de base */ - return result; + content = G_FILE_CONTENT(pygobject_get(self)); + + if (!g_file_content_create(content, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create file content.")); + return -1; + } + + return 0; } @@ -161,7 +174,9 @@ PyTypeObject *get_python_file_content_type(void) .tp_methods = py_file_content_methods, .tp_getset = py_file_content_getseters, - .tp_new = py_file_content_new + + .tp_init = py_file_content_init, + .tp_new = py_file_content_new, }; @@ -196,7 +211,10 @@ bool ensure_python_file_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_memory_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_FILE_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/contents/memory.c b/plugins/pychrysalide/analysis/contents/memory.c index 8926300..7464779 100644 --- a/plugins/pychrysalide/analysis/contents/memory.c +++ b/plugins/pychrysalide/analysis/contents/memory.c @@ -28,40 +28,43 @@ #include <pygobject.h> -#include <analysis/contents/memory.h> +#include <i18n.h> +#include <analysis/contents/memory-int.h> +#include "../content.h" #include "../../access.h" #include "../../helpers.h" -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_memory_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(memory_content, G_TYPE_MEMORY_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_memory_content_init(PyObject *, PyObject *, PyObject *); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_memory_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_memory_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ const char *data; /* Tampon interne de Python */ - int length; /* Taille utilisé de ce tampon */ + Py_ssize_t length; /* Taille utilisé de ce tampon */ int ret; /* Bilan de lecture des args. */ - GBinContent *content; /* Version GLib du contenu */ + GMemoryContent *content; /* Version GLib du contenu */ #define MEMORY_CONTENT_DOC \ "MemoryContent builds a binary content from memory data only." \ @@ -74,22 +77,32 @@ static PyObject *py_memory_content_new(PyTypeObject *type, PyObject *args, PyObj "Where data is provided as string or read-only bytes-like object." \ " The string may contain embedded null bytes." + /* Récupération des paramètres */ + /** * La taille doit être de type 'int' et non 'Py_ssize_t', sinon les 32 bits * de poids fort ne sont pas initialisés ! */ ret = PyArg_ParseTuple(args, "s#", &data, &length); - if (!ret) return NULL; + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ - content = g_memory_content_new((const bin_t *)data, length); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - result = pygobject_new(G_OBJECT(content)); + /* Eléments de base */ - if (content != NULL) - g_object_unref(content); + content = G_MEMORY_CONTENT(pygobject_get(self)); - return result; + if (!g_memory_content_create(content, (const bin_t *)data, length)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create memory content.")); + return -1; + } + + return 0; } @@ -129,7 +142,9 @@ PyTypeObject *get_python_memory_content_type(void) .tp_methods = py_memory_content_methods, .tp_getset = py_memory_content_getseters, - .tp_new = py_memory_content_new + + .tp_init = py_memory_content_init, + .tp_new = py_memory_content_new, }; @@ -152,7 +167,7 @@ PyTypeObject *get_python_memory_content_type(void) bool ensure_python_memory_content_is_registered(void) { - PyTypeObject *type; /* Type Python 'MemoryContent' */ + PyTypeObject *type; /* Type Python 'MemoryContent' */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ @@ -164,7 +179,10 @@ bool ensure_python_memory_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_MEMORY_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_binary_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_MEMORY_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/contents/restricted.c b/plugins/pychrysalide/analysis/contents/restricted.c index bbe364a..4521578 100644 --- a/plugins/pychrysalide/analysis/contents/restricted.c +++ b/plugins/pychrysalide/analysis/contents/restricted.c @@ -31,7 +31,8 @@ #include <i18n.h> -#include <analysis/contents/restricted.h> +#include <i18n.h> +#include <analysis/contents/restricted-int.h> #include "../content.h" @@ -41,8 +42,10 @@ -/* Crée un nouvel objet Python de type 'BinContent'. */ -static PyObject *py_restricted_content_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(restricted_content, G_TYPE_RESTRICTED_CONTENT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_restricted_content_init(PyObject *, PyObject *, PyObject *); /* Indique l'espace de restriction appliqué à un contenu. */ static PyObject *py_restricted_content_get_range(PyObject *, void *); @@ -51,25 +54,24 @@ static PyObject *py_restricted_content_get_range(PyObject *, void *); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'BinContent'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_restricted_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_restricted_content_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - GBinContent *content; /* Instance GLib correspondante*/ + GBinContent *internal; /* Instance GLib correspondante*/ mrange_t range; /* Restriction à appliquer */ int ret; /* Bilan de lecture des args. */ - GBinContent *restricted; /* Création GLib à transmettre */ + GRestrictedContent *content; /* Version GLib du contenu */ #define RESTRICTED_CONTENT_DOC \ "RestrictedContent restricts access to a given area for a binary content." \ @@ -81,14 +83,27 @@ static PyObject *py_restricted_content_new(PyTypeObject *type, PyObject *args, P "Where content is a pychrysalide.analysis.BinContent instance and range" \ " a Python object which can be converted into pychrysalide.arch.mrange." - ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &content, convert_any_to_mrange, &range); - if (!ret) return NULL; + /* Récupération des paramètres */ - restricted = g_restricted_content_new(content, &range); + ret = PyArg_ParseTuple(args, "O&O&", convert_to_binary_content, &internal, convert_any_to_mrange, &range); + if (!ret) return -1; - result = pygobject_new(G_OBJECT(restricted)); + /* Initialisation d'un objet GLib */ - return result; + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + content = G_RESTRICTED_CONTENT(pygobject_get(self)); + + if (!g_restricted_content_create(content, internal, &range)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create restricted content.")); + return -1; + } + + return 0; } @@ -165,7 +180,9 @@ PyTypeObject *get_python_restricted_content_type(void) .tp_methods = py_restricted_content_methods, .tp_getset = py_restricted_content_getseters, - .tp_new = py_restricted_content_new + + .tp_init = py_restricted_content_init, + .tp_new = py_restricted_content_new, }; @@ -200,7 +217,10 @@ bool ensure_python_restricted_content_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_RESTRICTED_CONTENT, type, &PyGObject_Type)) + if (!ensure_python_binary_content_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_RESTRICTED_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/Makefile.am b/plugins/pychrysalide/analysis/db/Makefile.am index fdf491e..a0dcc0d 100644 --- a/plugins/pychrysalide/analysis/db/Makefile.am +++ b/plugins/pychrysalide/analysis/db/Makefile.am @@ -1,19 +1,22 @@ noinst_LTLIBRARIES = libpychrysaanalysisdb.la -libpychrysaanalysisdb_la_SOURCES = \ - certs.h certs.c \ - client.h client.c \ - collection.h collection.c \ - constants.h constants.c \ - item.h item.c \ - module.h module.c \ +libpychrysaanalysisdb_la_SOURCES = \ + admin.h admin.c \ + analyst.h analyst.c \ + certs.h certs.c \ + client.h client.c \ + collection.h collection.c \ + constants.h constants.c \ + item.h item.c \ + module.h module.c \ server.h server.c -libpychrysaanalysisdb_la_LIBADD = \ +libpychrysaanalysisdb_la_LIBADD = \ items/libpychrysaanalysisdbitems.la -libpychrysaanalysisdb_la_LDFLAGS = +libpychrysaanalysisdb_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -21,9 +24,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisdb_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = items diff --git a/plugins/pychrysalide/analysis/db/admin.c b/plugins/pychrysalide/analysis/db/admin.c new file mode 100644 index 0000000..10a150e --- /dev/null +++ b/plugins/pychrysalide/analysis/db/admin.c @@ -0,0 +1,317 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * admin.c - équivalent Python du fichier "analysis/db/admin.c" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "admin.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/db/admin.h> + + +#include "client.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* Crée un nouvel objet Python de type 'AdminClient'. */ +static PyObject *py_admin_client_new(PyTypeObject *, PyObject *, PyObject *); + +/* Effectue une demande de liste de binaires existants. */ +static PyObject *py_admin_client_request_existing_binaries(PyObject *, PyObject *); + +/* Fournit la liste des instantanés existants. */ +static PyObject *py_admin_client_get_existing_binaries(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'AdminClient'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_admin_client_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + GAdminClient *client; /* Serveur mis en place */ + +#define ADMIN_CLIENT_DOC \ + "AdminClient provides control of the registered binary contents available from a" \ + " server.\n" \ + "\n" \ + "Such clients must be authenticated and communications are encrypted using TLS.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " AdminClient()" \ + "\n" \ + "AdminClient instances emit the following signals:\n" \ + "* 'existing-binaries-updated'\n" \ + " This signal is emitted when the list of existing binaries on server side" \ + " has been updated following a user request.\n" \ + + client = g_admin_client_new(); + + if (client != NULL) + { + result = pygobject_new(G_OBJECT(client)); + g_object_unref(client); + } + else result = NULL; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Effectue une demande de liste de binaires existants. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_admin_client_request_existing_binaries(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GAdminClient *client; /* Version native du serveur */ + bool status; /* Bilan de l'opération */ + +#define ADMIN_CLIENT_REQUEST_EXISTING_BINARIES_METHOD PYTHON_METHOD_DEF \ +( \ + request_existing_binaries, "$self, /", \ + METH_NOARGS, py_admin_client, \ + "Ask the server for a list of all existing analyzed binaries" \ + " and returns the status of the request transmission." \ + "\n" \ + "A *existing-binaries-updated* signal is emitted when the" \ + " pychrysalide.analysis.db.AdminClient.existing_binaries attribute" \ + " gets ready for reading." \ +) + + client = G_ADMIN_CLIENT(pygobject_get(self)); + + status = g_admin_client_request_existing_binaries(client); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la liste des instantanés existants. * +* * +* Retour : Liste de binaires en place, vide si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_admin_client_get_existing_binaries(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GAdminClient *client; /* Version native du serveur */ + size_t count; /* Taille de cette liste */ + char **binaries; /* Liste des binaires présents */ + size_t i; /* Boucle de parcours */ + +#define ADMIN_CLIENT_EXISTING_BINARIES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + existing_binaries, py_admin_client, \ + "Provide the list of all exisiting binaries on the server side.\n" \ + "\n" \ + "The returned value is a tuple of strings or an empty tuple." \ +) + + client = G_ADMIN_CLIENT(pygobject_get(self)); + + binaries = g_admin_client_get_existing_binaries(client, &count); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + PyTuple_SetItem(result, i, PyUnicode_FromString(binaries[i])); + + if (binaries != NULL) + free(binaries); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_admin_client_type(void) +{ + static PyMethodDef py_admin_client_methods[] = { + ADMIN_CLIENT_REQUEST_EXISTING_BINARIES_METHOD, + { NULL } + }; + + static PyGetSetDef py_admin_client_getseters[] = { + ADMIN_CLIENT_EXISTING_BINARIES_ATTRIB, + { NULL } + }; + + static PyTypeObject py_admin_client_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.db.AdminClient", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = ADMIN_CLIENT_DOC, + + .tp_methods = py_admin_client_methods, + .tp_getset = py_admin_client_getseters, + .tp_new = py_admin_client_new, + + }; + + return &py_admin_client_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide....db.AdminClient'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_admin_client_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'AdminClient' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_admin_client_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.db"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_hub_client_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ADMIN_CLIENT, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en client administrateur. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_admin_client(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_admin_client_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to admin client"); + break; + + case 1: + *((GAdminClient **)dst) = G_ADMIN_CLIENT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/yaml/python/scalar.h b/plugins/pychrysalide/analysis/db/admin.h index 3812bd7..8a2dfeb 100644 --- a/plugins/yaml/python/scalar.h +++ b/plugins/pychrysalide/analysis/db/admin.h @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * scalar.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/scalar.h" + * admin.h - prototypes pour l'équivalent Python du fichier "analysis/db/admin.h" * * Copyright (C) 2019 Cyrille Bagard * @@ -22,8 +22,8 @@ */ -#ifndef _PLUGINS_YAML_PYTHON_SCALAR_H -#define _PLUGINS_YAML_PYTHON_SCALAR_H +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ADMIN_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ADMIN_H #include <Python.h> @@ -32,14 +32,14 @@ /* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_yaml_scalar_type(void); +PyTypeObject *get_python_admin_client_type(void); -/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlScalar'. */ -bool register_python_yaml_scalar(PyObject *); +/* Prend en charge l'objet 'pychrysalide.analysis.db.AdminClient'. */ +bool ensure_python_admin_client_is_registered(void); -/* Tente de convertir en noeud d'arborescence de format Yaml. */ -int convert_to_yaml_scalar(PyObject *, void *); +/* Tente de convertir en client administrateur. */ +int convert_to_admin_client(PyObject *, void *); -#endif /* _PLUGINS_YAML_PYTHON_SCALAR_H */ +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ADMIN_H */ diff --git a/plugins/pychrysalide/analysis/db/analyst.c b/plugins/pychrysalide/analysis/db/analyst.c new file mode 100644 index 0000000..f2860ed --- /dev/null +++ b/plugins/pychrysalide/analysis/db/analyst.c @@ -0,0 +1,965 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * analyst.c - équivalent Python du fichier "analysis/db/analyst.c" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "analyst.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/db/analyst-int.h> +#include <core/collections.h> + + +#include "client.h" +#include "collection.h" +#include "constants.h" +#include "../content.h" +#include "../loaded.h" +#include "../../access.h" +#include "../../helpers.h" +#include "../../struct.h" + + + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_analyst_client_init(PyObject *, PyObject *, PyObject *); + +/* Envoie un contenu binaire pour conservation côté serveur. */ +static PyObject *py_analyst_client_send_content(PyObject *, PyObject *); + +/* Effectue une demande de sauvegarde de l'état courant. */ +static PyObject *py_analyst_client_save(PyObject *, PyObject *); + +/* Active les éléments en amont d'un horodatage donné. */ +static PyObject *py_analyst_client_set_last_active(PyObject *, PyObject *); + +/* Définit la désignation d'un instantané donné. */ +static PyObject *py_analyst_client_set_snapshot_name(PyObject *, PyObject *); + +/* Définit la désignation d'un instantané donné. */ +static PyObject *py_analyst_client_set_snapshot_desc(PyObject *, PyObject *); + +/* Restaure un ancien instantané. */ +static PyObject *py_analyst_client_restore_snapshot(PyObject *, PyObject *); + +/* Crée un nouvel instantané à partir d'un autre. */ +static PyObject *py_analyst_client_create_snapshot(PyObject *, PyObject *); + +/* Supprime un ancien instantané. */ +static PyObject *py_analyst_client_remove_snapshot(PyObject *, PyObject *); + +/* Fournit la liste des instantanés existants. */ +static PyObject *py_analyst_client_get_snapshots(PyObject *, void *); + +/* Fournit l'identifiant de l'instantané courant. */ +static PyObject *py_analyst_client_get_current_snapshot(PyObject *, void *); + + + +CREATE_DYN_CONSTRUCTOR(analyst_client, G_TYPE_ANALYST_CLIENT); + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_analyst_client_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int result; /* Bilan à retourner */ + GLoadedContent *loaded; /* Contenu local déjà chargé */ + const char *hash; /* Empreinte du binaire visé */ + const char *class; /* Nature du contenu analysé */ + PyObject *list; /* Liste Python de collections */ + int ret; /* Bilan de lecture des args. */ + Py_ssize_t length; /* Nombre d'éléments collectés */ + GList *collections; /* Liste native de collections */ + Py_ssize_t i; /* Boucle de parcours */ + PyObject *item; /* Elément de la liste Python */ + GDbCollection *collec; /* Version équivalente native */ + GAnalystClient *client; /* Client mis en place */ + bool status; /* Bilan d'initialisation */ + +#define ANALYST_CLIENT_DOC \ + "AnalystClient provides and receives binary updates to and from a connected" \ + " to a server.\n" \ + "\n" \ + "Such clients must be authenticated and communications are encrypted using TLS.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " AnalystClient(hash, class, list, loaded=None)" \ + "\n" \ + "Where *hash* is a SHA256 fingerprint of the studied binary, *class* refers to" \ + " the nature description of the loaded content (as provided from" \ + " pychrysalide.analysis.LoadedContent.content_class), *list* is a list of" \ + " pychrysalide.analysis.db.DbCollection instances ; this kind of list can be" \ + " retrived with the pychrysalide.analysis.LoadedBinary.collections attribute." \ + " The *loaded* object is an optional local already loaded content which has to" \ + " be a pychrysalide.analysis.LoadedContent instance or *None*." \ + "\n" \ + "AnalystClient instances emit the following signals:\n" \ + "* 'snapshots-updated'\n" \ + " This signal is emitted when the snapshot list has evolved.\n" \ + "\n" \ + " Handlers are expected to have only one argument: the client managing the" \ + " updated snapshots.\n" \ + "* 'snapshot-changed'\n" \ + " This signal is emitted when the identifier of the current snapshot changed.\n" \ + "\n" \ + " Handlers are expected to have only one argument: the client managing the" \ + " snapshots." + + loaded = NULL; + + ret = PyArg_ParseTuple(args, "ssO|O&", &hash, &class, &list, convert_to_loaded_content, &loaded); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + if (!PySequence_Check(list)) + { + PyErr_SetString(PyExc_TypeError, _("The second argument must be a collection list")); + return -1; + } + + length = PySequence_Length(list); + + collections = NULL; + + for (i = 0; i < length; i++) + { + item = PySequence_GetItem(list, i); + + ret = convert_to_db_collection(item, &collec); + + Py_DECREF(item); + + if (ret != 1) + { + delete_collections_list(&collections); + result = -1; + goto exit; + } + + g_object_ref(G_OBJECT(collec)); + collections = g_list_append(collections, collec); + + } + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_setup(client, hash, class, collections, loaded); + + result = status ? 0 : -1; + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments fournis à l'appel. * +* * +* Description : Envoie un contenu binaire pour conservation côté serveur. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_send_content(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GBinContent *content; /* Contenu binaire à envoyer */ + int ret; /* Bilan de lecture des args. */ + GAnalystClient *client; /* Version native du serveur */ + bool status; /* Bilan de l'opération */ + +#define ANALYST_CLIENT_SEND_CONTENT_METHOD PYTHON_METHOD_DEF \ +( \ + send_content, "$self, content, /", \ + METH_VARARGS, py_analyst_client, \ + "Ask the server for saving the current state of the analyzed binary" \ + " and returns the status of the request transmission." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_binary_content, &content); + if (!ret) return NULL; + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_send_content(client, content); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Effectue une demande de sauvegarde de l'état courant. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_save(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GAnalystClient *client; /* Version native du serveur */ + bool status; /* Bilan de l'opération */ + +#define ANALYST_CLIENT_SAVE_METHOD PYTHON_METHOD_DEF \ +( \ + save, "$self, /", \ + METH_NOARGS, py_analyst_client, \ + "Ask the server for saving the current state of the analyzed binary" \ + " and returns the status of the request transmission." \ +) + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_save(client); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel à consulter. * +* * +* Description : Active les éléments en amont d'un horodatage donné. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_set_last_active(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + unsigned long long timestamp; /* Horodatage de limite */ + int ret; /* Bilan de lecture des args. */ + GAnalystClient *client; /* Version native du serveur */ + bool status; /* Bilan de l'opération */ + +#define ANALYST_CLIENT_SET_LAST_ACTIVE_METHOD PYTHON_METHOD_DEF \ +( \ + set_last_active, "$self, timestamp, /", \ + METH_VARARGS, py_analyst_client, \ + "Define the timestamp of the last active item in the collection" \ + " and returns the status of the request transmission." \ + "\n" \ + "This method should not be used directly. Prefer calling" \ + " pychrysalide.analysis.LoadedBinary.set_last_active() instead," \ + " as some items may be volatile and thus not handled by clients." \ +) + + ret = PyArg_ParseTuple(args, "K", ×tamp); + if (!ret) return NULL; + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_set_last_active(client, timestamp); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel à consulter. * +* * +* Description : Définit la désignation d'un instantané donné. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_set_snapshot_name(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *raw_id; /* Identifiant brut */ + const char *text; /* Texte fourni à transmettre */ + int ret; /* Bilan de lecture des args. */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'opération */ + GAnalystClient *client; /* Version native du serveur */ + +#define ANALYST_CLIENT_SET_SNAPSHOT_NAME_METHOD PYTHON_METHOD_DEF \ +( \ + set_snapshot_name, "$self, id, name, /", \ + METH_VARARGS, py_analyst_client, \ + "Ask the server for defining a new name of for a snapshot using its" \ + " identifier and returns the status of the request transmission." \ + "\n" \ + "A 'snapshots-updated' signal is emitted once the request has been" \ + " processed with success." \ +) + + ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); + if (!ret) return NULL; + + status = init_snapshot_id_from_text(&id, raw_id); + if (!status) + { + PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); + return NULL; + } + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_set_snapshot_name(client, &id, text); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel à consulter. * +* * +* Description : Définit la désignation d'un instantané donné. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_set_snapshot_desc(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *raw_id; /* Identifiant brut */ + const char *text; /* Texte fourni à transmettre */ + int ret; /* Bilan de lecture des args. */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'opération */ + GAnalystClient *client; /* Version native du serveur */ + +#define ANALYST_CLIENT_SET_SNAPSHOT_DESC_METHOD PYTHON_METHOD_DEF \ +( \ + set_snapshot_desc, "$self, id, desc, /", \ + METH_VARARGS, py_analyst_client, \ + "Ask the server for defining a new description for a snapshot using" \ + " its identifier and returns the status of the request transmission." \ + "\n" \ + "A 'snapshots-updated' signal is emitted once the request has been" \ + " processed with success." \ +) + + ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); + if (!ret) return NULL; + + status = init_snapshot_id_from_text(&id, raw_id); + if (!status) + { + PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); + return NULL; + } + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_set_snapshot_desc(client, &id, text); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel à consulter. * +* * +* Description : Restaure un ancien instantané. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_restore_snapshot(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *raw_id; /* Identifiant brut */ + int ret; /* Bilan de lecture des args. */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'opération */ + GAnalystClient *client; /* Version native du serveur */ + +#define ANALYST_CLIENT_RESTORE_SNAPSHOT_METHOD PYTHON_METHOD_DEF \ +( \ + restore_snapshot, "$self, id, /", \ + METH_VARARGS, py_analyst_client, \ + "Ask the server for restoring a given snapshot using" \ + " its identifier and returns the status of the request transmission." \ + "\n" \ + "A 'snapshot-changed' signal is emitted once the request has been" \ + " processed with success." \ +) + + ret = PyArg_ParseTuple(args, "s", &raw_id); + if (!ret) return NULL; + + status = init_snapshot_id_from_text(&id, raw_id); + if (!status) + { + PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); + return NULL; + } + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_restore_snapshot(client, &id); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel à consulter. * +* * +* Description : Crée un nouvel instantané à partir d'un autre. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_create_snapshot(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GAnalystClient *client; /* Version native du serveur */ + bool status; /* Bilan d'opération */ + +#define ANALYST_CLIENT_CREATE_SNAPSHOT_METHOD PYTHON_METHOD_DEF \ +( \ + create_snapshot, "$self, /", \ + METH_NOARGS, py_analyst_client, \ + "Ask the server for creating a new snapshot of the current state" \ + " and returns the status of the request transmission." \ + "\n" \ + "A 'snapshots-updated' signal is emitted once the request has been" \ + " processed with success." \ +) + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_create_snapshot(client); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = client à manipuler. * +* args = arguments d'appel à consulter. * +* * +* Description : Supprime un ancien instantané. * +* * +* Retour : True si la commande a bien été envoyée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_remove_snapshot(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *raw_id; /* Identifiant brut */ + int rec; /* Indicateur de récursivité */ + int ret; /* Bilan de lecture des args. */ + snapshot_id_t id; /* Identifiant utilisable */ + bool status; /* Bilan d'opération */ + GAnalystClient *client; /* Version native du serveur */ + +#define ANALYST_CLIENT_REMOVE_SNAPSHOT_METHOD PYTHON_METHOD_DEF \ +( \ + remove_snapshot, "$self, id, recursive, /", \ + METH_VARARGS, py_analyst_client, \ + "Ask the server for removing a given snapshot using" \ + " its identifier and returns the status of the request transmission." \ + "\n" \ + "If this removal has not to be recursive, all children snapshots get" \ + " reassigned to the parent snapshot of the target." \ + "\n" \ + "A 'snapshots-updated' signal is emitted once the request has been" \ + " processed with success." \ +) + + ret = PyArg_ParseTuple(args, "sp", &raw_id, &rec); + if (!ret) return NULL; + + status = init_snapshot_id_from_text(&id, raw_id); + if (!status) + { + PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); + return NULL; + } + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_remove_snapshot(client, &id, rec); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la liste des instantanés existants. * +* * +* Retour : Liste d'instantanés ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_get_snapshots(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GAnalystClient *client; /* Version native du serveur */ + snapshot_info_t *info; /* Liste d'instantanés présents*/ + size_t count; /* Taille de cette liste */ + bool status; /* Validité de cet identifiant */ + PyTypeObject *base; /* Modèle d'objet à créer */ + size_t i; /* Boucle de parcours */ + PyObject *item; /* Nouvelle description */ + char *text; /* Valeur textuelle à placer */ + PyObject *attrib; /* Attribut à constituer */ + int ret; /* Bilan d'une mise en place */ + bool failed; /* Détection d'une erreur */ + +#define ANALYST_CLIENT_SNAPSHOTS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + snapshots, py_analyst_client, \ + "List of all existing snapshots, provided as a tuple of pychrysalide.StructObject." \ + "\n" \ + "Each snapshot is characterised by the following properties :\n" \ + "* parent_id : identifier of the parent snapshot;\n" \ + "* id : identifier of the snapshot;\n" \ + "* created : timestamp of the creation date;\n" \ + "* name : name of the snapshot, or None;\n" \ + "* desc : description of the snapshot, or None." \ +) + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_get_snapshots(client, &info, &count); + + if (status) + { + result = PyTuple_New(count); + + base = get_python_py_struct_type(); + + failed = false; + + for (i = 0; i < count; i++) + { + item = PyObject_CallFunction((PyObject *)base, NULL); + assert(item != NULL); + + text = snapshot_id_as_string(get_snapshot_info_parent_id(&info[i])); + attrib = PyUnicode_FromString(text); + ret = PyDict_SetItemString(item, "parent_id", attrib); + if (ret != 0) break; + + text = snapshot_id_as_string(get_snapshot_info_id(&info[i])); + attrib = PyUnicode_FromString(text); + ret = PyDict_SetItemString(item, "id", attrib); + if (ret != 0) break; + + attrib = PyLong_FromUnsignedLongLong(get_snapshot_info_created(&info[i])); + ret = PyDict_SetItemString(item, "created", attrib); + if (ret != 0) break; + + text = get_snapshot_info_name(&info[i]); + + if (text != NULL) + attrib = PyUnicode_FromString(text); + else + { + attrib = Py_None; + Py_INCREF(attrib); + } + + ret = PyDict_SetItemString(item, "name", attrib); + if (ret != 0) break; + + text = get_snapshot_info_desc(&info[i]); + + if (text != NULL) + attrib = PyUnicode_FromString(text); + else + { + attrib = Py_None; + Py_INCREF(attrib); + } + + ret = PyDict_SetItemString(item, "desc", attrib); + if (ret != 0) break; + + PyTuple_SetItem(result, i, item); + + } + + failed = (i < count); + + for (i = 0; i < count; i++) + exit_snapshot_info(&info[i]); + + free(info); + + if (failed) + goto on_failure; + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + + on_failure: + + Py_DECREF(result); + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit l'identifiant de l'instantané courant. * +* * +* Retour : Identifiant d'instantané ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_analyst_client_get_current_snapshot(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GAnalystClient *client; /* Version native du serveur */ + snapshot_id_t id; /* Identifiant à transmettre */ + bool status; /* Validité de cet identifiant */ + +#define ANALYST_CLIENT_CURRENT_SNAPSHOT_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + current_snapshot, py_analyst_client, \ + "Identifier of the current snapshot, provided as a string." \ + "\n" \ + "The returned value is a cached version of the value stored at" \ + " server side. Thus, defining a new current snapshot is" \ + " successful as soon as the request to this server is sent." \ +) + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_get_current_snapshot(client, &id); + + if (status) + result = PyUnicode_FromString(snapshot_id_as_string(&id)); + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Définit l'identifiant de l'instantané courant. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_analyst_client_set_current_snapshot(PyObject *self, PyObject *value, void *closure) +{ + int ret; /* Bilan d'analyse */ + void *raw; /* Valeur brute d'identifiant */ + snapshot_id_t id; /* Identifiant reconnu */ + bool status; /* Bilan d'une conversion */ + GAnalystClient *client; /* Version native du serveur */ + + ret = PyUnicode_Check(value); + if (!ret) return -1; + + raw = PyUnicode_DATA(value); + + status = init_snapshot_id_from_text(&id, raw); + if (!status) + { + PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); + return -1; + } + + client = G_ANALYST_CLIENT(pygobject_get(self)); + + status = g_analyst_client_set_current_snapshot(client, &id); + if (!status) + { + PyErr_SetString(PyExc_TypeError, "unable to send the provided snapshot identifier"); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_analyst_client_type(void) +{ + static PyMethodDef py_analyst_client_methods[] = { + ANALYST_CLIENT_SEND_CONTENT_METHOD, + ANALYST_CLIENT_SAVE_METHOD, + ANALYST_CLIENT_SET_LAST_ACTIVE_METHOD, + ANALYST_CLIENT_SET_SNAPSHOT_NAME_METHOD, + ANALYST_CLIENT_SET_SNAPSHOT_DESC_METHOD, + ANALYST_CLIENT_RESTORE_SNAPSHOT_METHOD, + ANALYST_CLIENT_CREATE_SNAPSHOT_METHOD, + ANALYST_CLIENT_REMOVE_SNAPSHOT_METHOD, + { NULL } + }; + + static PyGetSetDef py_analyst_client_getseters[] = { + ANALYST_CLIENT_SNAPSHOTS_ATTRIB, + ANALYST_CLIENT_CURRENT_SNAPSHOT_ATTRIB, + { NULL } + }; + + static PyTypeObject py_analyst_client_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.db.AnalystClient", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = ANALYST_CLIENT_DOC, + + .tp_methods = py_analyst_client_methods, + .tp_getset = py_analyst_client_getseters, + + .tp_init = py_analyst_client_init, + .tp_new = py_analyst_client_new + + }; + + return &py_analyst_client_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide....db.AnalystClient'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_analyst_client_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'AnalystClient' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_analyst_client_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.db"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_hub_client_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ANALYST_CLIENT, type)) + return false; + + if (!define_loading_status_hint_constants(type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en client analyste. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_analyst_client(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_analyst_client_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to analyst client"); + break; + + case 1: + *((GAnalystClient **)dst) = G_ANALYST_CLIENT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/analyst.h b/plugins/pychrysalide/analysis/db/analyst.h new file mode 100644 index 0000000..b250933 --- /dev/null +++ b/plugins/pychrysalide/analysis/db/analyst.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * analyst.h - prototypes pour l'équivalent Python du fichier "analysis/db/analyst.h" + * + * Copyright (C) 2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ANALYST_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ANALYST_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_analyst_client_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.db.AnalystClient'. */ +bool ensure_python_analyst_client_is_registered(void); + +/* Tente de convertir en client analyste. */ +int convert_to_analyst_client(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_ANALYST_H */ diff --git a/plugins/pychrysalide/analysis/db/client.c b/plugins/pychrysalide/analysis/db/client.c index d5d8b48..7ef658e 100644 --- a/plugins/pychrysalide/analysis/db/client.c +++ b/plugins/pychrysalide/analysis/db/client.c @@ -41,84 +41,13 @@ -/* Crée un nouvel objet Python de type 'HubClient'. */ -static PyObject *py_hub_client_new(PyTypeObject *, PyObject *, PyObject *); - -/* Démarre la connexion à la base de données. */ -static PyObject *py_hub_client_start(PyObject *, PyObject *); - -/* Arrête la connexion à la base de données. */ -static PyObject *py_hub_client_stop(PyObject *, PyObject *); - -/* Effectue une demande de sauvegarde de l'état courant. */ -static PyObject *py_hub_client_save(PyObject *, PyObject *); - -/* Active les éléments en amont d'un horodatage donné. */ -static PyObject *py_hub_client_set_last_active(PyObject *, PyObject *); - -/* Définit la désignation d'un instantané donné. */ -static PyObject *py_hub_client_set_snapshot_name(PyObject *, PyObject *); - -/* Définit la désignation d'un instantané donné. */ -static PyObject *py_hub_client_set_snapshot_desc(PyObject *, PyObject *); - -/* Restaure un ancien instantané. */ -static PyObject *py_hub_client_restore_snapshot(PyObject *, PyObject *); - -/* Crée un nouvel instantané à partir d'un autre. */ -static PyObject *py_hub_client_create_snapshot(PyObject *, PyObject *); - -/* Supprime un ancien instantané. */ -static PyObject *py_hub_client_remove_snapshot(PyObject *, PyObject *); - -/* Fournit la liste des instantanés existants. */ -static PyObject *py_hub_client_get_snapshots(PyObject *, void *); - -/* Fournit l'identifiant de l'instantané courant. */ -static PyObject *py_hub_client_get_current_snapshot(PyObject *, void *); - - - -/****************************************************************************** -* * -* Paramètres : type = type de l'objet à instancier. * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Crée un nouvel objet Python de type 'HubClient'. * -* * -* Retour : Instance Python mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Instance à retourner */ - const char *hash; /* Empreinte du binaire visé */ - PyObject *list; /* Liste Python de collections */ - int ret; /* Bilan de lecture des args. */ - Py_ssize_t length; /* Nombre d'éléments collectés */ - GList *collections; /* Liste native de collections */ - Py_ssize_t i; /* Boucle de parcours */ - PyObject *item; /* Elément de la liste Python */ - GDbCollection *collec; /* Version équivalente native */ - GHubClient *client; /* Serveur mis en place */ - #define HUB_CLIENT_DOC \ "HubClient provides and receives binary updates to and from a connected" \ " to a server.\n" \ "\n" \ "Such clients must be authenticated and communications are encrypted using TLS.\n" \ "\n" \ - "Instances can be created using the following constructor:\n" \ - "\n" \ - " HubClient(hash, list)" \ - "\n" \ - "Where hash is a SHA256 fingerprint of the studied binary and list is a list of" \ - " pychrysalide.analysis.db.DbCollection instances ; this kind of list can be" \ - " retrived with the pychrysalide.analysis.LoadedBinary.collections attribute." \ + "Instances can be created directly." \ "\n" \ "HubClient instances emit the following signals:\n" \ "* 'snapshots-updated'\n" \ @@ -132,53 +61,14 @@ static PyObject *py_hub_client_new(PyTypeObject *type, PyObject *args, PyObject " Handlers are expected to have only one argument: the client managing the" \ " snapshots." - ret = PyArg_ParseTuple(args, "sO", &hash, &list); - if (!ret) return NULL; - - if (!PySequence_Check(list)) - { - PyErr_SetString(PyExc_TypeError, _("The second argument must be a collection list")); - return NULL; - } - - length = PySequence_Length(list); - - collections = NULL; - - for (i = 0; i < length; i++) - { - item = PySequence_GetItem(list, i); - - ret = convert_to_db_collection(item, &collec); - - Py_DECREF(item); - if (ret != 1) - { - delete_collections_list(&collections); - result = NULL; - goto exit; - } - g_object_ref(G_OBJECT(collec)); - collections = g_list_append(collections, collec); - - } - - client = g_hub_client_new(hash, collections); - - if (client != NULL) - { - result = pygobject_new(G_OBJECT(client)); - g_object_unref(client); - } - else result = NULL; - - exit: +/* Démarre la connexion à la base de données. */ +static PyObject *py_hub_client_start(PyObject *, PyObject *); - return result; +/* Arrête la connexion à la base de données. */ +static PyObject *py_hub_client_stop(PyObject *, PyObject *); -} /****************************************************************************** @@ -275,588 +165,6 @@ static PyObject *py_hub_client_stop(PyObject *self, PyObject *args) /****************************************************************************** * * -* Paramètres : self = client à manipuler. * -* args = arguments d'appel non utilisés ici. * -* * -* Description : Effectue une demande de sauvegarde de l'état courant. * -* * -* Retour : True si la commande a bien été envoyée, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_save(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - GHubClient *client; /* Version native du serveur */ - bool status; /* Bilan de l'opération */ - -#define HUB_CLIENT_SAVE_METHOD PYTHON_METHOD_DEF \ -( \ - save, "$self, /", \ - METH_NOARGS, py_hub_client, \ - "Ask the server for saving the current state of the analyzed binary" \ - " and returns the status of the request transmission." \ -) - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_save(client); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = client à manipuler. * -* args = arguments d'appel à consulter. * -* * -* Description : Active les éléments en amont d'un horodatage donné. * -* * -* Retour : True si la commande a bien été envoyée, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_set_last_active(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - unsigned long long timestamp; /* Horodatage de limite */ - int ret; /* Bilan de lecture des args. */ - GHubClient *client; /* Version native du serveur */ - bool status; /* Bilan de l'opération */ - -#define HUB_CLIENT_SET_LAST_ACTIVE_METHOD PYTHON_METHOD_DEF \ -( \ - set_last_active, "$self, timestamp, /", \ - METH_VARARGS, py_hub_client, \ - "Define the timestamp of the last active item in the collection" \ - " and returns the status of the request transmission." \ - "\n" \ - "This method should not be used directly. Prefer calling" \ - " pychrysalide.analysis.LoadedBinary.set_last_active() instead," \ - " as some items may be volatile and thus not handled by clients." \ -) - - ret = PyArg_ParseTuple(args, "K", ×tamp); - if (!ret) return NULL; - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_set_last_active(client, timestamp); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = client à manipuler. * -* args = arguments d'appel à consulter. * -* * -* Description : Définit la désignation d'un instantané donné. * -* * -* Retour : True si la commande a bien été envoyée, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_set_snapshot_name(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - const char *raw_id; /* Identifiant brut */ - const char *text; /* Texte fourni à transmettre */ - int ret; /* Bilan de lecture des args. */ - snapshot_id_t id; /* Identifiant utilisable */ - bool status; /* Bilan d'opération */ - GHubClient *client; /* Version native du serveur */ - -#define HUB_CLIENT_SET_SNAPSHOT_NAME_METHOD PYTHON_METHOD_DEF \ -( \ - set_snapshot_name, "$self, id, name, /", \ - METH_VARARGS, py_hub_client, \ - "Ask the server for defining a new name of for a snapshot using its" \ - " identifier and returns the status of the request transmission." \ - "\n" \ - "A 'snapshots-updated' signal is emitted once the request has been" \ - " processed with success." \ -) - - ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); - if (!ret) return NULL; - - status = init_snapshot_id_from_text(&id, raw_id); - if (!status) - { - PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); - return NULL; - } - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_set_snapshot_name(client, &id, text); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = client à manipuler. * -* args = arguments d'appel à consulter. * -* * -* Description : Définit la désignation d'un instantané donné. * -* * -* Retour : True si la commande a bien été envoyée, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_set_snapshot_desc(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - const char *raw_id; /* Identifiant brut */ - const char *text; /* Texte fourni à transmettre */ - int ret; /* Bilan de lecture des args. */ - snapshot_id_t id; /* Identifiant utilisable */ - bool status; /* Bilan d'opération */ - GHubClient *client; /* Version native du serveur */ - -#define HUB_CLIENT_SET_SNAPSHOT_DESC_METHOD PYTHON_METHOD_DEF \ -( \ - set_snapshot_desc, "$self, id, desc, /", \ - METH_VARARGS, py_hub_client, \ - "Ask the server for defining a new description for a snapshot using" \ - " its identifier and returns the status of the request transmission." \ - "\n" \ - "A 'snapshots-updated' signal is emitted once the request has been" \ - " processed with success." \ -) - - ret = PyArg_ParseTuple(args, "ss", &raw_id, &text); - if (!ret) return NULL; - - status = init_snapshot_id_from_text(&id, raw_id); - if (!status) - { - PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); - return NULL; - } - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_set_snapshot_desc(client, &id, text); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = client à manipuler. * -* args = arguments d'appel à consulter. * -* * -* Description : Restaure un ancien instantané. * -* * -* Retour : True si la commande a bien été envoyée, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_restore_snapshot(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - const char *raw_id; /* Identifiant brut */ - int ret; /* Bilan de lecture des args. */ - snapshot_id_t id; /* Identifiant utilisable */ - bool status; /* Bilan d'opération */ - GHubClient *client; /* Version native du serveur */ - -#define HUB_CLIENT_RESTORE_SNAPSHOT_METHOD PYTHON_METHOD_DEF \ -( \ - restore_snapshot, "$self, id, /", \ - METH_VARARGS, py_hub_client, \ - "Ask the server for restoring a given snapshot using" \ - " its identifier and returns the status of the request transmission." \ - "\n" \ - "A 'snapshot-changed' signal is emitted once the request has been" \ - " processed with success." \ -) - - ret = PyArg_ParseTuple(args, "s", &raw_id); - if (!ret) return NULL; - - status = init_snapshot_id_from_text(&id, raw_id); - if (!status) - { - PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); - return NULL; - } - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_restore_snapshot(client, &id); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = client à manipuler. * -* args = arguments d'appel à consulter. * -* * -* Description : Crée un nouvel instantané à partir d'un autre. * -* * -* Retour : True si la commande a bien été envoyée, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_create_snapshot(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - GHubClient *client; /* Version native du serveur */ - bool status; /* Bilan d'opération */ - -#define HUB_CLIENT_CREATE_SNAPSHOT_METHOD PYTHON_METHOD_DEF \ -( \ - create_snapshot, "$self, /", \ - METH_NOARGS, py_hub_client, \ - "Ask the server for creating a new snapshot of the current state" \ - " and returns the status of the request transmission." \ - "\n" \ - "A 'snapshots-updated' signal is emitted once the request has been" \ - " processed with success." \ -) - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_create_snapshot(client); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = client à manipuler. * -* args = arguments d'appel à consulter. * -* * -* Description : Supprime un ancien instantané. * -* * -* Retour : True si la commande a bien été envoyée, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_remove_snapshot(PyObject *self, PyObject *args) -{ - PyObject *result; /* Bilan à retourner */ - const char *raw_id; /* Identifiant brut */ - int rec; /* Indicateur de récursivité */ - int ret; /* Bilan de lecture des args. */ - snapshot_id_t id; /* Identifiant utilisable */ - bool status; /* Bilan d'opération */ - GHubClient *client; /* Version native du serveur */ - -#define HUB_CLIENT_REMOVE_SNAPSHOT_METHOD PYTHON_METHOD_DEF \ -( \ - remove_snapshot, "$self, id, recursive, /", \ - METH_VARARGS, py_hub_client, \ - "Ask the server for removing a given snapshot using" \ - " its identifier and returns the status of the request transmission." \ - "\n" \ - "If this removal has not to be recursive, all children snapshots get" \ - " reassigned to the parent snapshot of the target." \ - "\n" \ - "A 'snapshots-updated' signal is emitted once the request has been" \ - " processed with success." \ -) - - ret = PyArg_ParseTuple(args, "sp", &raw_id, &rec); - if (!ret) return NULL; - - status = init_snapshot_id_from_text(&id, raw_id); - if (!status) - { - PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); - return NULL; - } - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_remove_snapshot(client, &id, rec); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit la liste des instantanés existants. * -* * -* Retour : Liste d'instantanés ou None. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_get_snapshots(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GHubClient *client; /* Version native du serveur */ - snapshot_info_t *info; /* Liste d'instantanés présents*/ - size_t count; /* Taille de cette liste */ - bool status; /* Validité de cet identifiant */ - PyTypeObject *base; /* Modèle d'objet à créer */ - size_t i; /* Boucle de parcours */ - PyObject *item; /* Nouvelle description */ - char *text; /* Valeur textuelle à placer */ - PyObject *attrib; /* Attribut à constituer */ - int ret; /* Bilan d'une mise en place */ - bool failed; /* Détection d'une erreur */ - -#define HUB_CLIENT_SNAPSHOTS_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - snapshots, py_hub_client, \ - "List of all existing snapshots, provided as a tuple of pychrysalide.StructObject." \ - "\n" \ - "Each snapshot is characterised by the following properties :\n" \ - "* parent_id : identifier of the parent snapshot;\n" \ - "* id : identifier of the snapshot;\n" \ - "* created : timestamp of the creation date;\n" \ - "* name : name of the snapshot, or None;\n" \ - "* desc : description of the snapshot, or None." \ -) - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_get_snapshots(client, &info, &count); - - if (status) - { - result = PyTuple_New(count); - - base = get_python_py_struct_type(); - - failed = false; - - for (i = 0; i < count; i++) - { - item = PyObject_CallFunction((PyObject *)base, NULL); - assert(item != NULL); - - text = snapshot_id_as_string(get_snapshot_info_parent_id(&info[i])); - attrib = PyUnicode_FromString(text); - ret = PyDict_SetItemString(item, "parent_id", attrib); - if (ret != 0) break; - - text = snapshot_id_as_string(get_snapshot_info_id(&info[i])); - attrib = PyUnicode_FromString(text); - ret = PyDict_SetItemString(item, "id", attrib); - if (ret != 0) break; - - attrib = PyLong_FromUnsignedLongLong(get_snapshot_info_created(&info[i])); - ret = PyDict_SetItemString(item, "created", attrib); - if (ret != 0) break; - - text = get_snapshot_info_name(&info[i]); - - if (text != NULL) - attrib = PyUnicode_FromString(text); - else - { - attrib = Py_None; - Py_INCREF(attrib); - } - - ret = PyDict_SetItemString(item, "name", attrib); - if (ret != 0) break; - - text = get_snapshot_info_desc(&info[i]); - - if (text != NULL) - attrib = PyUnicode_FromString(text); - else - { - attrib = Py_None; - Py_INCREF(attrib); - } - - ret = PyDict_SetItemString(item, "desc", attrib); - if (ret != 0) break; - - PyTuple_SetItem(result, i, item); - - } - - failed = (i < count); - - for (i = 0; i < count; i++) - exit_snapshot_info(&info[i]); - - free(info); - - if (failed) - goto on_failure; - - } - - else - { - result = Py_None; - Py_INCREF(result); - } - - return result; - - on_failure: - - Py_DECREF(result); - - return NULL; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit l'identifiant de l'instantané courant. * -* * -* Retour : Identifiant d'instantané ou None. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_hub_client_get_current_snapshot(PyObject *self, void *closure) -{ - PyObject *result; /* Valeur à retourner */ - GHubClient *client; /* Version native du serveur */ - snapshot_id_t id; /* Identifiant à transmettre */ - bool status; /* Validité de cet identifiant */ - -#define HUB_CLIENT_CURRENT_SNAPSHOT_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - current_snapshot, py_hub_client, \ - "Identifier of the current snapshot, provided as a string." \ - "\n" \ - "The returned value is a cached version of the value stored at" \ - " server side. Thus, defining a new current snapshot is" \ - " successful as soon as the request to this server is sent." \ -) - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_get_current_snapshot(client, &id); - - if (status) - result = PyUnicode_FromString(snapshot_id_as_string(&id)); - - else - { - result = Py_None; - Py_INCREF(result); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* value = valeur fournie à intégrer ou prendre en compte. * -* closure = adresse non utilisée ici. * -* * -* Description : Définit l'identifiant de l'instantané courant. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_hub_client_set_current_snapshot(PyObject *self, PyObject *value, void *closure) -{ - int ret; /* Bilan d'analyse */ - void *raw; /* Valeur brute d'identifiant */ - snapshot_id_t id; /* Identifiant reconnu */ - bool status; /* Bilan d'une conversion */ - GHubClient *client; /* Version native du serveur */ - - ret = PyUnicode_Check(value); - if (!ret) return -1; - - raw = PyUnicode_DATA(value); - - status = init_snapshot_id_from_text(&id, raw); - if (!status) - { - PyErr_SetString(PyExc_TypeError, _("provided value is not a valid snapshot identifier.")); - return -1; - } - - client = G_HUB_CLIENT(pygobject_get(self)); - - status = g_hub_client_set_current_snapshot(client, &id); - if (!status) - { - PyErr_SetString(PyExc_TypeError, "unable to send the provided snapshot identifier"); - return -1; - } - - return 0; - -} - - -/****************************************************************************** -* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -872,19 +180,10 @@ PyTypeObject *get_python_hub_client_type(void) static PyMethodDef py_hub_client_methods[] = { HUB_CLIENT_START_METHOD, HUB_CLIENT_STOP_METHOD, - HUB_CLIENT_SAVE_METHOD, - HUB_CLIENT_SET_LAST_ACTIVE_METHOD, - HUB_CLIENT_SET_SNAPSHOT_NAME_METHOD, - HUB_CLIENT_SET_SNAPSHOT_DESC_METHOD, - HUB_CLIENT_RESTORE_SNAPSHOT_METHOD, - HUB_CLIENT_CREATE_SNAPSHOT_METHOD, - HUB_CLIENT_REMOVE_SNAPSHOT_METHOD, { NULL } }; static PyGetSetDef py_hub_client_getseters[] = { - HUB_CLIENT_SNAPSHOTS_ATTRIB, - HUB_CLIENT_CURRENT_SNAPSHOT_ATTRIB, { NULL } }; @@ -901,7 +200,7 @@ PyTypeObject *get_python_hub_client_type(void) .tp_methods = py_hub_client_methods, .tp_getset = py_hub_client_getseters, - .tp_new = py_hub_client_new, + .tp_new = no_python_constructor_allowed, }; @@ -936,7 +235,7 @@ bool ensure_python_hub_client_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_HUB_CLIENT, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_HUB_CLIENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/collection.c b/plugins/pychrysalide/analysis/db/collection.c index ca4151c..5970d15 100644 --- a/plugins/pychrysalide/analysis/db/collection.c +++ b/plugins/pychrysalide/analysis/db/collection.c @@ -165,7 +165,7 @@ bool ensure_python_db_collection_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DB_COLLECTION, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DB_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/constants.c b/plugins/pychrysalide/analysis/db/constants.c index 8e7765a..5e8c20d 100644 --- a/plugins/pychrysalide/analysis/db/constants.c +++ b/plugins/pychrysalide/analysis/db/constants.c @@ -25,6 +25,7 @@ #include "constants.h" +#include <analysis/db/analyst.h> #include <analysis/db/item.h> #include <analysis/db/server.h> @@ -152,3 +153,45 @@ bool define_hub_server_constants(PyTypeObject *type) return result; } + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes pour les indications de chargement. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_loading_status_hint_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "READY", LSH_READY); + if (result) result = add_const_to_group(values, "ON_WAIT_LIST", LSH_ON_WAIT_LIST); + if (result) result = add_const_to_group(values, "NEED_CONTENT", LSH_NEED_CONTENT); + if (result) result = add_const_to_group(values, "NEED_FORMAT", LSH_NEED_FORMAT); + if (result) result = add_const_to_group(values, "NEED_ARCH", LSH_NEED_ARCH); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type_with_pyg_enum(type, false, "LoadingStatusHint", values, + "Indication about a loading process state.", + G_TYPE_LOADING_STATUS_HINT); + + exit: + + return result; + +} diff --git a/plugins/pychrysalide/analysis/db/constants.h b/plugins/pychrysalide/analysis/db/constants.h index 5f0afeb..ea7a0c0 100644 --- a/plugins/pychrysalide/analysis/db/constants.h +++ b/plugins/pychrysalide/analysis/db/constants.h @@ -39,6 +39,9 @@ bool define_db_item_constants(PyTypeObject *); /* Définit les constantes pour les serveurs de données. */ bool define_hub_server_constants(PyTypeObject *); +/* Définit les constantes pour les indications de chargement. */ +bool define_loading_status_hint_constants(PyTypeObject *); + #endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_DB_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/db/item.c b/plugins/pychrysalide/analysis/db/item.c index 836f902..cc9bdf4 100644 --- a/plugins/pychrysalide/analysis/db/item.c +++ b/plugins/pychrysalide/analysis/db/item.c @@ -369,7 +369,7 @@ bool ensure_python_db_item_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DB_ITEM, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DB_ITEM, type)) return false; if (!define_db_protocol_constants(type)) diff --git a/plugins/pychrysalide/analysis/db/items/Makefile.am b/plugins/pychrysalide/analysis/db/items/Makefile.am index 80f9756..201aed7 100644 --- a/plugins/pychrysalide/analysis/db/items/Makefile.am +++ b/plugins/pychrysalide/analysis/db/items/Makefile.am @@ -1,22 +1,17 @@ noinst_LTLIBRARIES = libpychrysaanalysisdbitems.la -libpychrysaanalysisdbitems_la_SOURCES = \ - bookmark.h bookmark.c \ - comment.h comment.c \ - constants.h constants.c \ - module.h module.c \ +libpychrysaanalysisdbitems_la_SOURCES = \ + bookmark.h bookmark.c \ + comment.h comment.c \ + constants.h constants.c \ + module.h module.c \ switcher.h switcher.c -libpychrysaanalysisdbitems_la_LDFLAGS = +libpychrysaanalysisdbitems_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisdbitems_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/analysis/db/items/bookmark.c b/plugins/pychrysalide/analysis/db/items/bookmark.c index af649e3..d2bc0f0 100644 --- a/plugins/pychrysalide/analysis/db/items/bookmark.c +++ b/plugins/pychrysalide/analysis/db/items/bookmark.c @@ -108,7 +108,7 @@ static PyObject *py_db_bookmark_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -366,7 +366,7 @@ bool ensure_python_db_bookmark_is_registered(void) if (!ensure_python_db_item_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_DB_BOOKMARK, type, get_python_db_item_type())) + if (!register_class_for_pygobject(dict, G_TYPE_DB_BOOKMARK, type)) return false; } @@ -473,7 +473,7 @@ static PyObject *py_bookmark_collection_new(PyTypeObject *type, PyObject *args, if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -570,7 +570,7 @@ bool ensure_python_bookmark_collection_is_registered(void) if (!ensure_python_db_collection_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BM_COLLECTION, type, get_python_db_collection_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BM_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/items/comment.c b/plugins/pychrysalide/analysis/db/items/comment.c index 78d4902..1358f1d 100644 --- a/plugins/pychrysalide/analysis/db/items/comment.c +++ b/plugins/pychrysalide/analysis/db/items/comment.c @@ -117,7 +117,7 @@ static PyObject *py_db_comment_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -464,7 +464,7 @@ bool ensure_python_db_comment_is_registered(void) if (!ensure_python_db_item_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_DB_COMMENT, type, get_python_db_item_type())) + if (!register_class_for_pygobject(dict, G_TYPE_DB_COMMENT, type)) return false; if (!define_db_comment_constants(type)) @@ -574,7 +574,7 @@ static PyObject *py_comment_collection_new(PyTypeObject *type, PyObject *args, P if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -671,7 +671,7 @@ bool ensure_python_comment_collection_is_registered(void) if (!ensure_python_db_collection_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_COMMENT_COLLECTION, type, get_python_db_collection_type())) + if (!register_class_for_pygobject(dict, G_TYPE_COMMENT_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/items/switcher.c b/plugins/pychrysalide/analysis/db/items/switcher.c index 6ac5cdf..5766fe1 100644 --- a/plugins/pychrysalide/analysis/db/items/switcher.c +++ b/plugins/pychrysalide/analysis/db/items/switcher.c @@ -114,7 +114,7 @@ static PyObject *py_db_switcher_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -398,7 +398,7 @@ bool ensure_python_db_switcher_is_registered(void) if (!ensure_python_db_item_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_DB_SWITCHER, type, get_python_db_item_type())) + if (!register_class_for_pygobject(dict, G_TYPE_DB_SWITCHER, type)) return false; } @@ -506,7 +506,7 @@ static PyObject *py_switcher_collection_new(PyTypeObject *type, PyObject *args, if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -603,7 +603,7 @@ bool ensure_python_switcher_collection_is_registered(void) if (!ensure_python_db_collection_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_SWITCHER_COLLECTION, type, get_python_db_collection_type())) + if (!register_class_for_pygobject(dict, G_TYPE_SWITCHER_COLLECTION, type)) return false; } diff --git a/plugins/pychrysalide/analysis/db/module.c b/plugins/pychrysalide/analysis/db/module.c index fa5a139..ddae5a7 100644 --- a/plugins/pychrysalide/analysis/db/module.c +++ b/plugins/pychrysalide/analysis/db/module.c @@ -28,6 +28,8 @@ #include <assert.h> +#include "admin.h" +#include "analyst.h" #include "certs.h" #include "client.h" #include "collection.h" @@ -98,6 +100,8 @@ bool populate_analysis_db_module(void) result = true; + if (result) result = ensure_python_admin_client_is_registered(); + if (result) result = ensure_python_analyst_client_is_registered(); if (result) result = ensure_python_certs_is_registered(); if (result) result = ensure_python_hub_client_is_registered(); if (result) result = ensure_python_db_collection_is_registered(); diff --git a/plugins/pychrysalide/analysis/db/server.c b/plugins/pychrysalide/analysis/db/server.c index 80ff4e2..dae7b29 100644 --- a/plugins/pychrysalide/analysis/db/server.c +++ b/plugins/pychrysalide/analysis/db/server.c @@ -83,7 +83,8 @@ static PyObject *py_hub_server_new(PyTypeObject *type, PyObject *args, PyObject "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " HubServer(host=None, port='1337', ipv6=True)" \ + " HubServer()" \ + " HubServer(host='localhost', port='1337', ipv6=True)" \ "\n" \ "Where host and port define the listening properties of the server, and ipv6" \ " tries to establish IPv6 connections first." \ @@ -273,7 +274,7 @@ bool ensure_python_hub_server_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_HUB_SERVER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_HUB_SERVER, type)) return false; if (!define_hub_server_constants(type)) diff --git a/plugins/pychrysalide/analysis/disass/Makefile.am b/plugins/pychrysalide/analysis/disass/Makefile.am index 0dacc15..0daa930 100644 --- a/plugins/pychrysalide/analysis/disass/Makefile.am +++ b/plugins/pychrysalide/analysis/disass/Makefile.am @@ -1,21 +1,14 @@ noinst_LTLIBRARIES = libpychrysaanalysisdisass.la -libpychrysaanalysisdisass_la_SOURCES = \ - block.h block.c \ +libpychrysaanalysisdisass_la_SOURCES = \ + block.h block.c \ module.h module.c -libpychrysaanalysisdisass_la_LDFLAGS = +libpychrysaanalysisdisass_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisdisass_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/analysis/disass/block.c b/plugins/pychrysalide/analysis/disass/block.c index 38e65a1..d82e3e2 100644 --- a/plugins/pychrysalide/analysis/disass/block.c +++ b/plugins/pychrysalide/analysis/disass/block.c @@ -159,7 +159,10 @@ bool ensure_python_basic_block_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BASIC_BLOCK, type, get_python_code_block_type())) + if (!ensure_python_code_block_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BASIC_BLOCK, type)) return false; } diff --git a/plugins/pychrysalide/analysis/loaded.c b/plugins/pychrysalide/analysis/loaded.c index 3ed51d5..a2bf13f 100644 --- a/plugins/pychrysalide/analysis/loaded.c +++ b/plugins/pychrysalide/analysis/loaded.c @@ -35,6 +35,7 @@ #include <analysis/loaded-int.h> #include <core/global.h> +#include <plugins/dt.h> #include "content.h" @@ -47,14 +48,17 @@ /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Procède à l'initialisation de l'interface de génération. */ -static void py_loaded_content_interface_init(GLoadedContentIface *, gpointer *); +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_loaded_content_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise la classe générique des contenus chargés. */ +static void py_loaded_content_init_gclass(GLoadedContentClass *, gpointer); /* Fournit le contenu représenté de l'élément chargé. */ static GBinContent *py_loaded_content_get_content_wrapper(const GLoadedContent *); -/* Fournit le format associé à l'élément chargé. */ -static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *); +/* Décrit la nature du contenu reconnu pour l'élément chargé. */ +static char *py_loaded_content_get_content_class_wrapper(const GLoadedContent *, bool); /* Lance l'analyse propre à l'élément chargé. */ static bool py_loaded_content_analyze_wrapper(GLoadedContent *, bool, bool, wgroup_id_t, GtkStatusStack *); @@ -62,6 +66,8 @@ static bool py_loaded_content_analyze_wrapper(GLoadedContent *, bool, bool, wgro /* Fournit le désignation associée à l'élément chargé. */ static char *py_loaded_content_describe_wrapper(const GLoadedContent *, bool); +#ifdef INCLUDE_GTK_SUPPORT + /* Détermine le nombre de vues disponibles pour un contenu. */ static unsigned int py_loaded_content_count_views_wrapper(const GLoadedContent *); @@ -77,6 +83,8 @@ static GtkWidget *py_loaded_content_build_view_wrapper(GLoadedContent *, unsigne /* Retrouve l'indice correspondant à la vue donnée d'un contenu. */ static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *, GtkWidget *); +#endif + /* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ @@ -94,6 +102,8 @@ static PyObject *py_loaded_content_describe(PyObject *, PyObject *); /* Etablit une liste d'obscurcissements présents. */ static PyObject *py_loaded_content_detect_obfuscators(PyObject *, PyObject *); +#ifdef INCLUDE_GTK_SUPPORT + /* Détermine le nombre de vues disponibles pour un contenu. */ static PyObject *py_loaded_content_count_views(PyObject *, PyObject *); @@ -106,11 +116,16 @@ static PyObject *py_loaded_content_build_default_view(PyObject *, PyObject *); /* Met en place la vue initiale pour un contenu chargé. */ static PyObject *py_loaded_content_build_view(PyObject *, PyObject *); +#endif + /* Fournit le contenu représenté de l'élément chargé. */ static PyObject *py_loaded_content_get_content(PyObject *, void *); -/* Fournit le format associé à l'élément chargé. */ -static PyObject *py_loaded_content_get_format_name(PyObject *, void *); +/* Décrit la nature du contenu reconnu pour l'élément chargé. */ +static PyObject *py_loaded_content_get_content_class(PyObject *, void *); + +/* Décrit la nature du contenu reconnu pour l'élément chargé. */ +static PyObject *py_loaded_content_get_content_class_for_human(PyObject *, void *); @@ -121,21 +136,28 @@ static PyObject *py_loaded_content_get_format_name(PyObject *, void *); /****************************************************************************** * * -* Paramètres : iface = interface GLib à initialiser. * -* unused = adresse non utilisée ici. * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * * * -* Description : Procède à l'initialisation de l'interface de génération. * +* Description : Accompagne la création d'une instance dérivée en Python. * * * -* Retour : - * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -static void py_loaded_content_interface_init(GLoadedContentIface *iface, gpointer *unused) +static PyObject *py_loaded_content_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type de base à dériver */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + #define LOADED_CONTENT_DOC \ - "The LoadedContent interface is an intermediary level of abstraction" \ + "The LoadedContent object is an intermediary level of abstraction" \ " for all loaded binary contents to analyze." \ "\n" \ "No matter if the loaded content comes from an ELF file or XML data," \ @@ -148,7 +170,7 @@ static void py_loaded_content_interface_init(GLoadedContentIface *iface, gpointe "\n" \ "The following methods have to be defined for new implementations:\n" \ "* pychrysalide.analysis.storage.LoadedContent._get_content();\n" \ - "* pychrysalide.analysis.storage.LoadedContent._get_format_name();\n" \ + "* pychrysalide.analysis.storage.LoadedContent._get_content_class();\n" \ "* pychrysalide.analysis.storage.LoadedContent._analyze();\n" \ "* pychrysalide.analysis.storage.LoadedContent._describe();\n" \ "* pychrysalide.analysis.storage.LoadedContent._count_views();\n" \ @@ -157,18 +179,76 @@ static void py_loaded_content_interface_init(GLoadedContentIface *iface, gpointe "* pychrysalide.analysis.storage.LoadedContent._build_view();\n" \ "* pychrysalide.analysis.storage.LoadedContent._get_view_index();\n" - iface->get_content = py_loaded_content_get_content_wrapper; - iface->get_format_name = py_loaded_content_get_format_name_wrapper; + /* Validations diverses */ + + base = get_python_loaded_content_type(); + + if (type == base) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); + goto exit; + } - iface->analyze = py_loaded_content_analyze_wrapper; + /* Mise en place d'un type dédié */ - iface->describe = py_loaded_content_describe_wrapper; + first_time = (g_type_from_name(type->tp_name) == 0); - iface->count_views = py_loaded_content_count_views_wrapper; - iface->get_view_name = py_loaded_content_get_view_name_wrapper; - iface->build_def_view = py_loaded_content_build_default_view_wrapper; - iface->build_view = py_loaded_content_build_view_wrapper; - iface->get_view_index = py_loaded_content_get_view_index_wrapper; + gtype = build_dynamic_type(G_TYPE_LOADED_CONTENT, type->tp_name, + (GClassInitFunc)py_loaded_content_init_gclass, NULL, NULL); + + if (first_time) + { + status = register_class_for_dynamic_pygobject(gtype, type); + + if (!status) + { + result = NULL; + goto exit; + } + + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe générique des contenus chargés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_loaded_content_init_gclass(GLoadedContentClass *class, gpointer unused) +{ + class->get_content = py_loaded_content_get_content_wrapper; + class->get_content_class = py_loaded_content_get_content_class_wrapper; + + class->analyze = py_loaded_content_analyze_wrapper; + + class->describe = py_loaded_content_describe_wrapper; + +#ifdef INCLUDE_GTK_SUPPORT + class->count_views = py_loaded_content_count_views_wrapper; + class->get_view_name = py_loaded_content_get_view_name_wrapper; + class->build_def_view = py_loaded_content_build_default_view_wrapper; + class->build_view = py_loaded_content_build_view_wrapper; + class->get_view_index = py_loaded_content_get_view_index_wrapper; +#endif } @@ -234,31 +314,34 @@ static GBinContent *py_loaded_content_get_content_wrapper(const GLoadedContent * /****************************************************************************** * * * Paramètres : content = élément chargé à manipuler. * +* human = description humaine attendue ? * * * -* Description : Fournit le format associé à l'élément chargé. * +* Description : Décrit la nature du contenu reconnu pour l'élément chargé. * * * -* Retour : Format associé à l'élément chargé. * +* Retour : Classe de contenu associée à l'élément chargé. * * * * Remarques : - * * * ******************************************************************************/ -static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *content) +static char *py_loaded_content_get_content_class_wrapper(const GLoadedContent *content, bool human) { char *result; /* Contenu interne à renvoyer */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *hobj; /* Argument pour Python */ PyObject *pyret; /* Bilan de consultation */ int ret; /* Validité d'une conversion */ -#define LOADED_CONTENT_GET_FORMAT_NAME_WRAPPER PYTHON_WRAPPER_DEF \ +#define LOADED_CONTENT_GET_CONTENT_CLASS_WRAPPER PYTHON_WRAPPER_DEF \ ( \ - _get_format_name, "$self", \ + _get_content_class, "$self, human", \ METH_VARARGS, \ - "Abstract method used to provide the aw name of the format connected" \ - " to the loaded content.\n" \ + "Abstract method used to provide the nature of the loaded content.\n" \ "\n" \ - "The name associated to a loaded Elf binary is for instance 'elf'." \ + "The description associated to a loaded ARM Elf binary is for instance" \ + " 'elf-armv7', or 'Elf, ARMv7' for the human version." \ ) result = NULL; @@ -267,9 +350,16 @@ static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *con pyobj = pygobject_new(G_OBJECT(content)); - if (has_python_method(pyobj, "_get_format_name")) + if (has_python_method(pyobj, "_get_content_class")) { - pyret = run_python_method(pyobj, "_get_format_name", NULL); + args = PyTuple_New(1); + + hobj = (human ? Py_True : Py_False); + Py_INCREF(hobj); + + PyTuple_SetItem(args, 0, hobj); + + pyret = run_python_method(pyobj, "_get_content_class", args); if (pyret != NULL) { @@ -282,6 +372,8 @@ static char *py_loaded_content_get_format_name_wrapper(const GLoadedContent *con } + Py_DECREF(args); + } Py_DECREF(pyobj); @@ -456,6 +548,9 @@ static char *py_loaded_content_describe_wrapper(const GLoadedContent *content, b } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : content = contenu chargé à consulter. * @@ -792,6 +887,9 @@ static unsigned int py_loaded_content_get_view_index_wrapper(GLoadedContent *con } +#endif + + /* ---------------------------------------------------------------------------------- */ /* CONNEXION AVEC L'API DE PYTHON */ @@ -876,7 +974,6 @@ static PyObject *py_loaded_content_analyze_and_wait(PyObject *self, PyObject *ar int connect; /* Connexion à la base ? */ int cache; /* Préparation de rendu ? */ int ret; /* Bilan de lecture des args. */ - PyThreadState *_save; /* Sauvegarde de contexte */ GLoadedContent *content; /* Version GLib de l'élément */ bool status; /* Bilan de l'opération */ @@ -911,12 +1008,8 @@ static PyObject *py_loaded_content_analyze_and_wait(PyObject *self, PyObject *ar content = G_LOADED_CONTENT(pygobject_get(self)); - Py_UNBLOCK_THREADS; - status = g_loaded_content_analyze_and_wait(content, connect, cache); - Py_BLOCK_THREADS; - result = status ? Py_True : Py_False; Py_INCREF(result); @@ -1030,6 +1123,9 @@ static PyObject *py_loaded_content_detect_obfuscators(PyObject *self, PyObject * } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : self = contenu chargé à manipuler. * @@ -1271,6 +1367,9 @@ static PyObject *py_loaded_content_get_view_index(PyObject *self, PyObject *args } +#endif + + /****************************************************************************** * * * Paramètres : self = objet Python concerné par l'appel. * @@ -1314,35 +1413,77 @@ static PyObject *py_loaded_content_get_content(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Fournit le format associé à l'élément chargé. * +* Description : Décrit la nature du contenu reconnu pour l'élément chargé. * * * -* Retour : Format associé à l'élément chargé. * +* Retour : Classe de contenu associée à l'élément chargé. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_loaded_content_get_format_name(PyObject *self, void *closure) +static PyObject *py_loaded_content_get_content_class(PyObject *self, void *closure) { PyObject *result; /* Instance Python à retourner */ GLoadedContent *content; /* Version GLib de l'élément */ - GBinContent *bincnt; /* Contenu binaire associé */ + char *class; /* Nature du contenu binaire */ -#define LOADED_CONTENT_FORMAT_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +#define LOADED_CONTENT_CONTENT_CLASS_ATTRIB PYTHON_GET_DEF_FULL \ ( \ - format_name, py_loaded_content, \ - "Raw name of the format connected to the loaded content.\n" \ + content_class, py_loaded_content, \ + "Nature of the loaded content.\n" \ "\n" \ - "The name associated to a loaded Elf binary is for instance 'elf'." \ + "The description associated to a loaded ARM Elf binary is for instance" \ + " 'elf-armv7'." \ ) content = G_LOADED_CONTENT(pygobject_get(self)); - bincnt = g_loaded_content_get_content(content); + class = g_loaded_content_get_content_class(content, false); - result = pygobject_new(G_OBJECT(bincnt)); + result = PyUnicode_FromString(class); - g_object_unref(G_OBJECT(bincnt)); + free(class); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Décrit la nature du contenu reconnu pour l'élément chargé. * +* * +* Retour : Classe de contenu associée à l'élément chargé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_loaded_content_get_content_class_for_human(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GLoadedContent *content; /* Version GLib de l'élément */ + char *class; /* Nature du contenu binaire */ + +#define LOADED_CONTENT_CONTENT_CLASS_FOR_HUMAN_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + content_class_for_human, py_loaded_content, \ + "Humain version of the nature of the loaded content.\n" \ + "\n" \ + "The description associated to a loaded ARM Elf binary is for instance" \ + " ''Elf, ARMv7'." \ +) + + content = G_LOADED_CONTENT(pygobject_get(self)); + + class = g_loaded_content_get_content_class(content, true); + + result = PyUnicode_FromString(class); + + free(class); return result; @@ -1365,29 +1506,34 @@ PyTypeObject *get_python_loaded_content_type(void) { static PyMethodDef py_loaded_content_methods[] = { LOADED_CONTENT_GET_CONTENT_WRAPPER, - LOADED_CONTENT_GET_FORMAT_NAME_WRAPPER, + LOADED_CONTENT_GET_CONTENT_CLASS_WRAPPER, LOADED_CONTENT_ANALYZE_WRAPPER, LOADED_CONTENT_DESCRIBE_WRAPPER, +#ifdef INCLUDE_GTK_SUPPORT LOADED_CONTENT_COUNT_VIEWS_WRAPPER, LOADED_CONTENT_GET_VIEW_NAME_WRAPPER, LOADED_CONTENT_BUILD_DEFAULT_VIEW_WRAPPER, LOADED_CONTENT_BUILD_VIEW_WRAPPER, LOADED_CONTENT_GET_VIEW_INDEX_WRAPPER, +#endif LOADED_CONTENT_ANALYZE_METHOD, LOADED_CONTENT_ANALYZE_AND_WAIT_METHOD, LOADED_CONTENT_DESCRIBE_METHOD, LOADED_CONTENT_DETECT_OBFUSCATORS_METHOD, +#ifdef INCLUDE_GTK_SUPPORT LOADED_CONTENT_COUNT_VIEWS_METHOD, LOADED_CONTENT_GET_VIEW_NAME_METHOD, LOADED_CONTENT_BUILD_DEFAULT_VIEW_METHOD, LOADED_CONTENT_BUILD_VIEW_METHOD, LOADED_CONTENT_GET_VIEW_INDEX_METHOD, +#endif { NULL } }; static PyGetSetDef py_loaded_content_getseters[] = { LOADED_CONTENT_CONTENT_ATTRIB, - LOADED_CONTENT_FORMAT_NAME_ATTRIB, + LOADED_CONTENT_CONTENT_CLASS_ATTRIB, + LOADED_CONTENT_CONTENT_CLASS_FOR_HUMAN_ATTRIB, { NULL } }; @@ -1396,14 +1542,16 @@ PyTypeObject *get_python_loaded_content_type(void) PyVarObject_HEAD_INIT(NULL, 0) .tp_name = "pychrysalide.analysis.LoadedContent", - .tp_basicsize = sizeof(PyObject), + .tp_basicsize = sizeof(PyGObject), - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, .tp_doc = LOADED_CONTENT_DOC, .tp_methods = py_loaded_content_methods, - .tp_getset = py_loaded_content_getseters + .tp_getset = py_loaded_content_getseters, + + .tp_new = py_loaded_content_new, }; @@ -1430,14 +1578,6 @@ bool ensure_python_loaded_content_is_registered(void) PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - static GInterfaceInfo info = { /* Paramètres d'inscription */ - - .interface_init = (GInterfaceInitFunc)py_loaded_content_interface_init, - .interface_finalize = NULL, - .interface_data = NULL, - - }; - type = get_python_loaded_content_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) @@ -1446,10 +1586,12 @@ bool ensure_python_loaded_content_is_registered(void) dict = PyModule_GetDict(module); +#ifdef INCLUDE_GTK_SUPPORT if (!ensure_python_named_widget_is_registered()) return false; +#endif - if (!register_interface_for_pygobject(dict, G_TYPE_LOADED_CONTENT, type, &info)) + if (!register_class_for_pygobject(dict, G_TYPE_LOADED_CONTENT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/loading.c b/plugins/pychrysalide/analysis/loading.c index dea4e31..8a60d8a 100644 --- a/plugins/pychrysalide/analysis/loading.c +++ b/plugins/pychrysalide/analysis/loading.c @@ -168,7 +168,7 @@ bool ensure_python_content_explorer_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_EXPLORER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_EXPLORER, type)) return false; } @@ -294,7 +294,7 @@ bool ensure_python_content_resolver_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_RESOLVER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_RESOLVER, type)) return false; } diff --git a/plugins/pychrysalide/analysis/module.c b/plugins/pychrysalide/analysis/module.c index 9632956..6b8e441 100644 --- a/plugins/pychrysalide/analysis/module.c +++ b/plugins/pychrysalide/analysis/module.c @@ -41,6 +41,7 @@ #include "contents/module.h" #include "db/module.h" #include "disass/module.h" +#include "scan/module.h" #include "storage/module.h" #include "types/module.h" #include "../helpers.h" @@ -86,6 +87,7 @@ bool add_analysis_module(PyObject *super) if (result) result = add_analysis_contents_module(module); if (result) result = add_analysis_db_module(module); if (result) result = add_analysis_disass_module(module); + if (result) result = add_analysis_scan_module(module); if (result) result = add_analysis_storage_module(module); if (result) result = add_analysis_types_module(module); @@ -131,6 +133,7 @@ bool populate_analysis_module(void) if (result) result = populate_analysis_contents_module(); if (result) result = populate_analysis_db_module(); if (result) result = populate_analysis_disass_module(); + if (result) result = populate_analysis_scan_module(); if (result) result = populate_analysis_storage_module(); if (result) result = populate_analysis_types_module(); diff --git a/plugins/pychrysalide/analysis/project.c b/plugins/pychrysalide/analysis/project.c index e66119c..b00259a 100644 --- a/plugins/pychrysalide/analysis/project.c +++ b/plugins/pychrysalide/analysis/project.c @@ -402,7 +402,7 @@ bool ensure_python_study_project_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_STUDY_PROJECT, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_STUDY_PROJECT, type)) return false; } diff --git a/plugins/pychrysalide/analysis/routine.c b/plugins/pychrysalide/analysis/routine.c index e33ca90..535ba84 100644 --- a/plugins/pychrysalide/analysis/routine.c +++ b/plugins/pychrysalide/analysis/routine.c @@ -757,7 +757,7 @@ bool ensure_python_binary_routine_is_registered(void) if (!ensure_python_binary_symbol_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BIN_ROUTINE, type, get_python_binary_symbol_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_ROUTINE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/scan/Makefile.am b/plugins/pychrysalide/analysis/scan/Makefile.am new file mode 100644 index 0000000..8c9fb77 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/Makefile.am @@ -0,0 +1,28 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscan.la + +libpychrysaanalysisscan_la_SOURCES = \ + constants.h constants.c \ + context.h context.c \ + core.h core.c \ + expr.h expr.c \ + item.h item.c \ + module.h module.c \ + options.h options.c \ + scanner.h scanner.c \ + space.h space.c + +libpychrysaanalysisscan_la_LIBADD = \ + exprs/libpychrysaanalysisscanexprs.la \ + patterns/libpychrysaanalysisscanpatterns.la + +libpychrysaanalysisscan_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscan_la_SOURCES:%c=) + + +SUBDIRS = exprs patterns diff --git a/plugins/pychrysalide/analysis/scan/constants.c b/plugins/pychrysalide/analysis/scan/constants.c new file mode 100644 index 0000000..d030df2 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/constants.c @@ -0,0 +1,128 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes de base pour les types + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "constants.h" + + +#include <analysis/scan/expr.h> + + +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux expressions de scan. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_expression_value_type_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "PENDING", SRS_PENDING); + if (result) result = add_const_to_group(values, "REDUCED", SRS_REDUCED); + if (result) result = add_const_to_group(values, "WAIT_FOR_SCAN", SRS_WAIT_FOR_SCAN); + if (result) result = add_const_to_group(values, "UNRESOLVABLE", SRS_UNRESOLVABLE); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "ScanReductionState", values, + "State of a scanexpression during the reduction process."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en constante ScanReductionState. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_reduction_state(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur transcrite */ + + result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ScanReductionState"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > SRS_UNRESOLVABLE) + { + PyErr_SetString(PyExc_TypeError, "invalid value for ScanReductionState"); + result = 0; + } + + else + *((ScanReductionState *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/constants.h b/plugins/pychrysalide/analysis/scan/constants.h new file mode 100644 index 0000000..aa6c571 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes de base pour les types + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit les constantes relatives aux expressions de scan. */ +bool define_expression_value_type_constants(PyTypeObject *); + +/* Tente de convertir en constante ScanReductionState. */ +int convert_to_scan_reduction_state(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_TYPES_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/scan/context.c b/plugins/pychrysalide/analysis/scan/context.c new file mode 100644 index 0000000..9becaf7 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/context.c @@ -0,0 +1,432 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.c - équivalent Python du fichier "analysis/scan/context.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "context.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/context-int.h> +#include <analysis/scan/expr.h> + +#include "expr.h" +#include "../content.h" +#include "../../access.h" +#include "../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_context, G_TYPE_SCAN_CONTEXT); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_context_init(PyObject *, PyObject *, PyObject *); + +/* Note que la phase d'analyse de contenu est terminée. */ +static PyObject *py_scan_context_mark_scan_as_done(PyObject *, PyObject *); + +/* Indique si une correspondance globale a pu être établie. */ +static PyObject *py_scan_context_has_match_for_rule(PyObject *, PyObject *); + +/* Fournit une référence au contenu principal analysé. */ +static PyObject *py_scan_context_get_content(PyObject *, void *); + +/* Définit le contenu principal à analyser. */ +static int py_scan_context_set_content(PyObject *, PyObject *, void *); + +/* Indique si la phase d'analyse de contenu est terminée. */ +static PyObject *py_scan_context_is_scan_done(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_context_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_CONTEXT_DOC \ + "A ScanContext object tracks results of a run analysis process" \ + " against binary contents.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanContext()" + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, ""); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Note que la phase d'analyse de contenu est terminée. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_mark_scan_as_done(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanContext *context; /* Contexte de suivi d'analyse */ + +#define SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD PYTHON_METHOD_DEF \ +( \ + mark_scan_as_done, "$self", \ + METH_NOARGS, py_scan_context, \ + "Note that the analysis operations are finished." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + g_scan_context_mark_scan_as_done(context); + + result = Py_None; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Indique si une correspondance globale a pu être établie. * +* * +* Retour : Bilan final d'une analyse (False par défaut). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_has_match_for_rule(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + const char *name; /* Désignation de règle */ + int ret; /* Bilan de lecture des args. */ + GScanContext *context; /* Contexte de suivi d'analyse */ + bool matched; /* Bilan d'analyse à renvoyer */ + +#define SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD PYTHON_METHOD_DEF \ +( \ + has_match_for_rule, "$self, name, /", \ + METH_VARARGS, py_scan_context, \ + "Provide the match status for a given scan rule.\n" \ + "\n" \ + "The *name* argument points to the registered rule to query.\n" \ + "\n" \ + "The method returns the scan final status as a boolean: *True*" \ + " in case of match, *False* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return NULL; + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + matched = g_scan_context_has_match_for_rule(context, name); + + result = matched ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une routine binaire. * +* closure = adresse non utilisée ici. * +* * +* Description : Fournit une référence au contenu principal analysé. * +* * +* Retour : Content binaire associé au context. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_get_content(PyObject *self, void *closure) +{ + PyObject *result; /* Eléments à retourner */ + GScanContext *context; /* Version native */ + GBinContent *content; /* Contenu binaire à référencer*/ + +#define SCAN_CONTEXT_CONTENT_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + content, py_scan_context, \ + "Link to the scanned binary content.\n" \ + "\n" \ + "The result is a pychrysalide.analysis.BinContent for" \ + " fully initialized context." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + content = g_scan_context_get_content(context); + + result = pygobject_new(G_OBJECT(content)); + + g_object_unref(G_OBJECT(content)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = non utilisé ici. * +* * +* Description : Définit le contenu principal à analyser. * +* * +* Retour : Content binaire associé au context. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_context_set_content(PyObject *self, PyObject *value, void *closure) +{ + GScanContext *context; /* Elément à consulter */ + int ret; /* Bilan de lecture des args. */ + GBinContent *content; /* Contenu binaire à référencer*/ + + ret = PyObject_IsInstance(value, (PyObject *)get_python_binary_content_type()); + if (!ret) return -1; + + context = G_SCAN_CONTEXT(pygobject_get(self)); + content = G_BIN_CONTENT(pygobject_get(value)); + + // FIXME g_scan_context_set_content(context, content); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique si la phase d'analyse de contenu est terminée. * +* * +* Retour : True si la phase de scan est terminée, False sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_context_is_scan_done(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GScanContext *context; /* Contexte de suivi d'analyse */ + bool status; /* Bilan de consultation */ + +#define SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB PYTHON_IS_DEF_FULL \ +( \ + scan_done, py_scan_context, \ + "Tell if the analysis operations are finished.\n" \ + "\n" \ + "The result is a boolean: *True* if the scan is marked as" \ + " done, *False* otherwise." \ +) + + context = G_SCAN_CONTEXT(pygobject_get(self)); + + status = g_scan_context_is_scan_done(context); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_context_type(void) +{ + static PyMethodDef py_scan_context_methods[] = { + SCAN_CONTEXT_MARK_SCAN_AS_DONE_METHOD, + SCAN_CONTEXT_HAS_MATCH_FOR_RULE_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_context_getseters[] = { + SCAN_CONTEXT_CONTENT_ATTRIB, + SCAN_CONTEXT_IS_SCAN_DONE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_context_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanContext", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_CONTEXT_DOC, + + .tp_methods = py_scan_context_methods, + .tp_getset = py_scan_context_getseters, + + .tp_init = py_scan_context_init, + .tp_new = py_scan_context_new, + + }; + + return &py_scan_context_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide.....scan.ScanContext. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_context_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanContext' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_context_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_CONTEXT, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en contexte de suivi d'analyse. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_context(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_context_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan context"); + break; + + case 1: + *((GScanContext **)dst) = G_SCAN_CONTEXT(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/context.h b/plugins/pychrysalide/analysis/scan/context.h new file mode 100644 index 0000000..477205b --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/context.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * context.h - prototypes pour l'équivalent Python du fichier "analysis/scan/context.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_context_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanContext'. */ +bool ensure_python_scan_context_is_registered(void); + +/* Tente de convertir en contexte de suivi d'analyse. */ +int convert_to_scan_context(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_CONTEXT_H */ diff --git a/plugins/pychrysalide/analysis/scan/core.c b/plugins/pychrysalide/analysis/scan/core.c new file mode 100644 index 0000000..16df9a9 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/core.c @@ -0,0 +1,179 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - équivalent Python du fichier "analysis/scan/core.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "core.h" + + +#include <pygobject.h> + + +#include <analysis/scan/core.h> + + +#include "patterns/modifier.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* Inscrit un modificateur dans la liste des disponibles. */ +static PyObject *py_scan_register_token_modifier(PyObject *, PyObject *); + +/* Fournit le modificateur correspondant à un nom. */ +static PyObject *py_scan_find_token_modifiers_for_name(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Inscrit un modificateur dans la liste des disponibles. * +* * +* Retour : Bilan des enregistrements effectués : True si nouveauté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_register_token_modifier(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + PyObject *instance; /* Instance Python fournie */ + GScanTokenModifier *modifier; /* Version native */ + int ret; /* Bilan de lecture des args. */ + bool status; /* Bilan d'un enregistrement */ + +#define SCAN_REGISTER_TOKEN_MODIFIER_METHOD PYTHON_METHOD_DEF \ +( \ + register_token_modifier, "inst, /", \ + METH_VARARGS, py_scan, \ + "Register a token modifier for byte patterns to scan.\n" \ + "\n" \ + "This instance will be used as singleton and has to be a" \ + " subclass of pychrysalide.analysis.scan.patterns.TokenModifier." \ +) + + ret = PyArg_ParseTuple(args, "O!", get_python_scan_token_modifier_type(), &instance); + if (!ret) return NULL; + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(instance)); + + status = register_scan_token_modifier(modifier); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Fournit le modificateur correspondant à un nom. * +* * +* Retour : Instance du modificateur identifié ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_find_token_modifiers_for_name(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + sized_string_t name; /* Nom d'appel à rechercher */ + Py_ssize_t len; /* Taille de ce nom */ + int ret; /* Bilan de lecture des args. */ + GScanTokenModifier *modifier; /* Instance mise en place */ + +#define SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD PYTHON_METHOD_DEF \ +( \ + find_token_modifiers_for_name, "name, /", \ + METH_VARARGS, py_scan, \ + "Provide the registered instance of a pattern modifier linked" \ + " to a given *name* provided as a key string.\n" \ + "\n" \ + "The returned instance is an object inherited from" \ + " pychrysalide.analysis.scan.patterns.TokenModifier or *None*" \ + " if no instance was found for the provided name." \ +) + + ret = PyArg_ParseTuple(args, "s#", &name.static_data, &len); + if (!ret) return NULL; + + name.len = len; + + modifier = find_scan_token_modifiers_for_name(&name); + + if (modifier != NULL) + { + result = pygobject_new(G_OBJECT(modifier)); + g_object_unref(G_OBJECT(modifier)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'scan' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_scan_module_with_core_methods(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_core_methods[] = { + SCAN_REGISTER_TOKEN_MODIFIER_METHOD, + SCAN_FIND_TOKEN_MODIFIERS_FOR_NAME_METHOD, + { NULL } + }; + + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + result = register_python_module_methods(module, py_core_methods); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/core.h b/plugins/pychrysalide/analysis/scan/core.h new file mode 100644 index 0000000..e283f91 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/core.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour l'équivalent Python du fichier "analysis/scan/core.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_CORE_CORE_H +#define _PLUGINS_PYCHRYSALIDE_CORE_CORE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit une extension du module 'scan' à compléter. */ +bool populate_scan_module_with_core_methods(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_CORE_CORE_H */ diff --git a/plugins/pychrysalide/analysis/scan/expr.c b/plugins/pychrysalide/analysis/scan/expr.c new file mode 100644 index 0000000..2d8245a --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/expr.c @@ -0,0 +1,393 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.c - équivalent Python du fichier "analysis/scan/expr.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "expr.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/expr-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> +#include <plugins/pychrysalide/glibext/comparison.h> + + +#include "constants.h" + + + +/* Initialise la classe générique des expressions d'évaluation. */ +static void py_scan_expression_init_gclass(GScanExpressionClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_expression, G_TYPE_SCAN_EXPRESSION, py_scan_expression_init_gclass); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_expression_init(PyObject *, PyObject *, PyObject *); + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *, const GScanExpression *, RichCmpOperation, bool *); + +/* Indique l'état de réduction d'une expression. */ +static PyObject *py_scan_expression_get_state(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe générique des expressions d'évaluation. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_scan_expression_init_gclass(GScanExpressionClass *class, gpointer unused) +{ + class->cmp_rich = py_scan_expression_compare_rich_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_expression_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + ScanReductionState state; /* Etat de réduction initial */ + int ret; /* Bilan de lecture des args. */ + GScanExpression *expr; /* Création GLib à transmettre */ + + static char *kwlist[] = { "state", NULL }; + +#define SCAN_EXPRESSION_DOC \ + "A ScanExpression is an abstract object which defines an expression"\ + " involved in data matching when running a scan.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object expect"\ + " the following arguments as keyword parameters:\n" \ + "* *state*: initial state of reduction for the expression, as a" \ + " pychrysalide.analysis.scan.ScanExpression.ScanReductionState" \ + " value." \ + "\n" \ + "The following methods have to be defined for new classes:\n" \ + "* pychrysalide.analysis.scan.ScanExpression._cmp_rich().\n" + + /* Récupération des paramètres */ + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, convert_to_scan_reduction_state, &state); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + expr = G_SCAN_EXPRESSION(pygobject_get(self)); + + if (!g_scan_expression_create(expr, state)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create scan expression.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à cnsulter pour une comparaison. * +* other = second objet à cnsulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_expression_compare_rich_wrapper(const GScanExpression *item, const GScanExpression *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + +#define SCAN_EXPRESSION_CMP_RICH_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, other, op, /", \ + METH_VARARGS, \ + "Abstract method used to compare the expression against another" \ + " one.\n" \ + "\n" \ + "The second *other* instance is built from the same type as *self*."\ + " The *op* argument points to a" \ + " pychrysalide.glibext.ComparableItem.RichCmpOperation mode" \ + " describing the expected comparison.\n" \ + "\n" \ + "The result is a boolean status or *None* if the comparison" \ + " process is undefined." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_cmp_rich")) + { + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other))); + PyTuple_SetItem(args, 1, cast_with_constants_group_from_type(get_python_comparable_item_type(), + "RichCmpOperation", op)); + + pyret = run_python_method(pyobj, "_cmp_rich", args); + + if (pyret != NULL) + { + ret = PyBool_Check(pyret); + + if (ret) + { + *status = (pyret == Py_True); + result = true; + } + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique l'état de réduction d'une expression. * +* * +* Retour : Etat courant associé à l'expression. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_expression_get_state(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GScanExpression *expr; /* Version GLib de l'opérande */ + ScanReductionState state; /* Etat courant de l'expression*/ + +#define SCAN_EXPRESSION_STATE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + state, py_scan_expression, \ + "Current state of the expression, relative to the reduction" \ + " process, as a" \ + " pychrysalide.analysis.scan.ScanExpression.ScanReductionState" \ + " value." \ +) + + expr = G_SCAN_EXPRESSION(pygobject_get(self)); + + state = g_scan_expression_get_state(expr); + + result = cast_with_constants_group_from_type(get_python_scan_expression_type(), "ScanReductionState", state); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_expression_type(void) +{ + static PyMethodDef py_scan_expression_methods[] = { + SCAN_EXPRESSION_CMP_RICH_WRAPPER, + { NULL } + }; + + static PyGetSetDef py_scan_expression_getseters[] = { + SCAN_EXPRESSION_STATE_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_expression_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanExpression", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_EXPRESSION_DOC, + + .tp_methods = py_scan_expression_methods, + .tp_getset = py_scan_expression_getseters, + + .tp_init = py_scan_expression_init, + .tp_new = py_scan_expression_new, + + }; + + return &py_scan_expression_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanExpression'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_expression_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanExpression'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_expression_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_comparable_item_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_EXPRESSION, type)) + return false; + + if (!define_expression_value_type_constants(type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en expression d'évaluation généraliste. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_expression(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_expression_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to match expression"); + break; + + case 1: + *((GScanExpression **)dst) = G_SCAN_EXPRESSION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/expr.h b/plugins/pychrysalide/analysis/scan/expr.h new file mode 100644 index 0000000..42f5350 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/expr.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * expr.h - prototypes pour l'équivalent Python du fichier "analysis/scan/expr.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_expression_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanExpression'. */ +bool ensure_python_scan_expression_is_registered(void); + +/* Tente de convertir en expression d'évaluation généraliste. */ +int convert_to_scan_expression(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPR_H */ diff --git a/plugins/pychrysalide/analysis/scan/exprs/Makefile.am b/plugins/pychrysalide/analysis/scan/exprs/Makefile.am new file mode 100644 index 0000000..e40d4de --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanexprs.la + +libpychrysaanalysisscanexprs_la_SOURCES = \ + constants.h constants.c \ + literal.h literal.c \ + module.h module.c + +libpychrysaanalysisscanexprs_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + $(TOOLKIT_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanexprs_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/exprs/constants.c b/plugins/pychrysalide/analysis/scan/exprs/constants.c new file mode 100644 index 0000000..b11ac4c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/constants.c @@ -0,0 +1,128 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - ajout des constantes de base pour les expressions + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "constants.h" + + +#include <analysis/scan/exprs/literal.h> + + +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives aux expressions de scan. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_literal_expression_value_type_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "LVT_BOOLEAN", LVT_BOOLEAN); + if (result) result = add_const_to_group(values, "SIGNED_INTEGER", LVT_SIGNED_INTEGER); + if (result) result = add_const_to_group(values, "UNSIGNED_INTEGER", LVT_UNSIGNED_INTEGER); + if (result) result = add_const_to_group(values, "STRING", LVT_STRING); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "LiteralValueType", values, + "Type of value carried by a literal scan expression."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en constante LiteralValueType. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_literal_expression_value_type(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur transcrite */ + + result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to LiteralValueType"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > LVT_REG_EXPR) + { + PyErr_SetString(PyExc_TypeError, "invalid value for LiteralValueType"); + result = 0; + } + + else + *((LiteralValueType *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/exprs/constants.h b/plugins/pychrysalide/analysis/scan/exprs/constants.h new file mode 100644 index 0000000..e5b8e8c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour l'ajout des constantes de base pour les expressions + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit les constantes relatives aux expressions litérales. */ +bool define_literal_expression_value_type_constants(PyTypeObject *); + +/* Tente de convertir en constante LiteralValueType. */ +int convert_to_literal_expression_value_type(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_CONSTANTS_H */ diff --git a/plugins/pychrysalide/analysis/scan/exprs/literal.c b/plugins/pychrysalide/analysis/scan/exprs/literal.c new file mode 100644 index 0000000..d7ae002 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/literal.c @@ -0,0 +1,281 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.c - équivalent Python du fichier "analysis/scan/exprs/literal.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "literal.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/exprs/literal-int.h> + + +#include "constants.h" +#include "../expr.h" +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_literal_expression, G_TYPE_SCAN_LITERAL_EXPRESSION); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_literal_expression_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_literal_expression_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *py_value; /* Valeur en version Python */ + int ret; /* Bilan de lecture des args. */ + LiteralValueType vtype; /* Valeur à porter */ + bool arg_boolean; /* Argument natif booléen */ + unsigned long long arg_uinteger; /* Argument natif entier */ + sized_string_t arg_string; /* Argument natif textuel */ + Py_ssize_t arg_str_length; /* Taille de ce texte */ + void *arg_ptr; /* Pointeur vers un argument */ + GScanLiteralExpression *expr; /* Création GLib à transmettre */ + +#define SCAN_LITERAL_EXPRESSION_DOC \ + "A ScanLiteralExpression object defines expression carrying" \ + " literal values available for scan match conditions.\n" \ + "\n" \ + "Instances can be created using one of the following" \ + " constructors:\n" \ + "\n" \ + " ScanLiteralExpression(value)" \ + "\n" \ + "\n" \ + "Where *value* is either a boolean, an integer or bytes." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "O", &py_value); + if (!ret) return -1; + + if (PyBool_Check(py_value)) + { + vtype = LVT_BOOLEAN; + + arg_boolean = (py_value == Py_True); + arg_ptr = &arg_boolean; + + } + + else if (PyLong_Check(py_value)) + { + if (1 /* sign - TODO */) + ; + + vtype = LVT_UNSIGNED_INTEGER; + + arg_uinteger = PyLong_AsUnsignedLongLong(py_value); + arg_ptr = &arg_uinteger; + + } + + else if (PyBytes_Check(py_value)) + { + vtype = LVT_STRING; + + ret = PyBytes_AsStringAndSize(py_value, &arg_string.data, &arg_str_length); + if (ret == -1) return -1; + + arg_string.len = arg_str_length; + arg_ptr = &arg_string; + + } + + else + { + PyErr_SetString(PyExc_ValueError, _("Unsupported Python value for a literal scan expression.")); + return -1; + } + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + expr = G_SCAN_LITERAL_EXPRESSION(pygobject_get(self)); + + if (!g_scan_literal_expression_create(expr, vtype, arg_ptr)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create literal expression.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_literal_expression_type(void) +{ + static PyMethodDef py_scan_literal_expression_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_literal_expression_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_literal_expression_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.exprs.ScanLiteralExpression", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_LITERAL_EXPRESSION_DOC, + + .tp_methods = py_scan_literal_expression_methods, + .tp_getset = py_scan_literal_expression_getseters, + + .tp_init = py_scan_literal_expression_init, + .tp_new = py_scan_literal_expression_new, + + }; + + return &py_scan_literal_expression_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....PlainModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_literal_expression_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PlainModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_literal_expression_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.exprs"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_expression_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_LITERAL_EXPRESSION, type)) + return false; + + if (!define_literal_expression_value_type_constants(type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_literal_expression(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_literal_expression_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan literal expression"); + break; + + case 1: + *((GScanLiteralExpression **)dst) = G_SCAN_LITERAL_EXPRESSION(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/exprs/literal.h b/plugins/pychrysalide/analysis/scan/exprs/literal.h new file mode 100644 index 0000000..8e7ea70 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/literal.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * literal.h - équivalent Python du fichier "analysis/scan/exprs/literal.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_literal_expression_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.exprs.ScanLiteralExpression'. */ +bool ensure_python_scan_literal_expression_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_literal_expression(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_LITERAL_H */ diff --git a/plugins/pychrysalide/analysis/scan/exprs/module.c b/plugins/pychrysalide/analysis/scan/exprs/module.c new file mode 100644 index 0000000..4f38430 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/module.c @@ -0,0 +1,103 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire exprs en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "literal.h" +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis....modifiers' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_exprs_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_DOC \ + "This module provide expressions used to build a match condition." + + static PyModuleDef py_chrysalide_analysis_scan_exprs_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.exprs", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_exprs_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis...patterns.modifiers'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_exprs_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_literal_expression_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/exprs/module.h b/plugins/pychrysalide/analysis/scan/exprs/module.h new file mode 100644 index 0000000..ee4b8ab --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/exprs/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire exprs en tant que module + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.exprs' à un module Python. */ +bool add_analysis_scan_exprs_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.exprs'. */ +bool populate_analysis_scan_exprs_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_EXPRS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/item.c b/plugins/pychrysalide/analysis/scan/item.c new file mode 100644 index 0000000..014ae24 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/item.c @@ -0,0 +1,740 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.c - équivalent Python du fichier "analysis/scan/item.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "item.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/item-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "context.h" + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Initialise la classe des éléments appelables enregistrés. */ +static void py_scan_registered_item_init_gclass(GScanRegisteredItemClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_registered_item, G_TYPE_SCAN_REGISTERED_ITEM, py_scan_registered_item_init_gclass); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_registered_item_init(PyObject *, PyObject *, PyObject *); + +/* Indique le nom associé à une expression d'évaluation. */ +static char *py_scan_registered_item_get_name_wrapper(const GScanRegisteredItem *); + +/* Lance une résolution d'élément à solliciter. */ +static bool py_scan_registered_item_resolve_wrapper(GScanRegisteredItem *, const char *, GScanContext *, GScanScope *, GScanRegisteredItem **); + +/* Réduit une expression à une forme plus simple. */ +static bool py_scan_registered_item_reduce_wrapper(GScanRegisteredItem *, GScanContext *, GScanScope *, GScanExpression **); + +/* Effectue un appel à une fonction enregistrée. */ +static bool py_scan_registered_item_run_call_wrapper(GScanRegisteredItem *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **); + + + +/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ + + +/* Lance une résolution d'élément à appeler. */ +static PyObject *py_scan_registered_item_resolve(PyObject *, PyObject *); + +/* Fournit le désignation associée à un composant nommé. */ +static PyObject *py_scan_registered_item_get_name(PyObject *, void *); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * +* * +* Description : Initialise la classe des éléments appelables enregistrés. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_scan_registered_item_init_gclass(GScanRegisteredItemClass *class, gpointer unused) +{ + class->get_name = py_scan_registered_item_get_name_wrapper; + class->resolve = py_scan_registered_item_resolve_wrapper; + class->reduce = py_scan_registered_item_reduce_wrapper; + class->run_call = py_scan_registered_item_run_call_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_registered_item_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_REGISTERED_ITEM_DOC \ + "The *RegisteredItem* class is an abstract definition which is" \ + " the base for all keywords involved in a match condition" \ + " expression.\n" \ + "\n" \ + "Calls to the *__init__* constructor of this abstract object" \ + " expect no particular argument.\n" \ + "\n" \ + "The following methods have to be defined for new classes:\n" \ + "* pychrysalide.analysis.scan.RegisteredItem._resolve();\n" \ + "* pychrysalide.analysis.scan.RegisteredItem._reduce();\n" \ + "* pychrysalide.analysis.scan.RegisteredItem._call().\n" \ + "\n" \ + "One item has to be defined as class attributes in the final" \ + " class:\n" \ + "* pychrysalide.analysis.scan.RegisteredItem._name.\n" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* * +* Description : Indique le nom associé à une expression d'évaluation. * +* * +* Retour : Désignation humaine de l'expression d'évaluation. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_scan_registered_item_get_name_wrapper(const GScanRegisteredItem *item) +{ + char *result; /* Désignation à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyname; /* Nom en objet Python */ + int ret; /* Bilan d'une conversion */ + +#define SCAN_REGISTERED_ITEM_NAME_ATTRIB_WRAPPER PYTHON_GETTER_WRAPPER_DEF \ +( \ + _name, \ + "Provide the keyword of the expression item to be evaluated.\n" \ + "\n" \ + "The result has to be a string." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (PyObject_HasAttrString(pyobj, "_name")) + { + pyname = PyObject_GetAttrString(pyobj, "_name"); + + if (pyname != NULL) + { + ret = PyUnicode_Check(pyname); + + if (ret) + result = strdup(PyUnicode_AsUTF8(pyname)); + + Py_DECREF(pyname); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* target = désignation de l'objet d'appel à identifier. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT]* +* * +* Description : Lance une résolution d'élément à solliciter. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_registered_item_resolve_wrapper(GScanRegisteredItem *item, const char *target, GScanContext *ctx, GScanScope *scope, GScanRegisteredItem **out) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + GObject *gobj_ret; /* Bilan natif de consultation */ + +#define SCAN_REGISTERED_ITEM_RESOLVE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, target, ctx, scope, /", \ + METH_VARARGS, \ + "Abstract method used to resolve an item by name.\n" \ + "\n" \ + "The *target* argument provide the name of the searched item;" \ + " *ctx* is a pychrysalide.analysis.scan.ScanContext instance" \ + " providing information about the current state; *scope* is a" \ + " pychrysalide.analysis.scan.ScanScope offering a view on the" \ + " current namespace for variables.\n" \ + "\n" \ + "The result has to be a pychrysalide.analysis.scan.RegisteredItem" \ + " instance on success, or *None* in case of failure." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_resolve")) + { + args = PyTuple_New(3); + PyTuple_SetItem(args, 0, PyUnicode_FromString(target)); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(ctx))); + PyTuple_SetItem(args, 2, pygobject_new(G_OBJECT(scope))); + + pyret = run_python_method(pyobj, "_resolve", args); + + if (pyret != NULL) + { + gobj_ret = pygobject_get(pyret); + + if (G_IS_SCAN_REGISTERED_ITEM(gobj_ret)) + { + *out = G_SCAN_REGISTERED_ITEM(gobj_ret); + + g_object_ref(G_OBJECT(*out)); + result = true; + + } + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la réduction opérée. [OUT] * +* * +* Description : Réduit une expression à une forme plus simple. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_registered_item_reduce_wrapper(GScanRegisteredItem *item, GScanContext *ctx, GScanScope *scope, GScanExpression **out) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + GObject *gobj_ret; /* Bilan natif de consultation */ + +#define SCAN_REGISTERED_ITEM_REDUCE_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, ctx, scope, /", \ + METH_VARARGS, \ + "Abstract method used to replace the item by an equivalent reduced" \ + " value.\n" \ + "\n" \ + "The *ctx* argument is a pychrysalide.analysis.scan.ScanContext" \ + " instance providing information about the current state; *scope*" \ + " is a pychrysalide.analysis.scan.ScanScope offering a view on the" \ + " current namespace for variables.\n" \ + "\n" \ + "The result has to be a pychrysalide.analysis.scan.ScanExpression" \ + " instance on success, or *None* in case of failure." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_reduce")) + { + args = PyTuple_New(2); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(ctx))); + PyTuple_SetItem(args, 1, pygobject_new(G_OBJECT(scope))); + + pyret = run_python_method(pyobj, "_reduce", args); + + if (pyret != NULL) + { + gobj_ret = pygobject_get(pyret); + + if (G_IS_SCAN_EXPRESSION(gobj_ret)) + { + *out = G_SCAN_EXPRESSION(gobj_ret); + + g_object_ref(G_OBJECT(*out)); + result = true; + + } + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : item = élément d'appel à consulter. * +* args = liste d'éventuels arguments fournis. * +* count = taille de cette liste. * +* ctx = contexte de suivi de l'analyse courante. * +* scope = portée courante des variables locales. * +* out = zone d'enregistrement de la résolution opérée. [OUT] * +* * +* Description : Effectue un appel à une fonction enregistrée. * +* * +* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_scan_registered_item_run_call_wrapper(GScanRegisteredItem *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out) +{ + bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *sub_args; /* Sous-arguments pour l'appel */ + size_t i; /* Boucle de parcours */ + PyObject *py_args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + GObject *gobj_ret; /* Bilan natif de consultation */ + +#define SCAN_REGISTERED_ITEM_CALL_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _cmp_rich, "$self, args, ctx, scope, /", \ + METH_VARARGS, \ + "Abstract method used to replace the item and its arguments by an" \ + " equivalent reduced value.\n" \ + "\n" \ + "The *args* argument is a tuple of already reduced" \ + " pychrysalide.analysis.scan.ScanExpression objects; ctx* argument" \ + " is a pychrysalide.analysis.scan.ScanContext instance providing" \ + " information about the current state; *scope* is a" \ + " pychrysalide.analysis.scan.ScanScope offering a view on the" \ + " current namespace for variables.\n" \ + "\n" \ + "The result has to be a pychrysalide.analysis.scan.ScanExpression" \ + " instance on success, or *None* in case of failure." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(item)); + + if (has_python_method(pyobj, "_call")) + { + sub_args = PyTuple_New(count); + + for (i = 0; i < count; i++) + PyTuple_SetItem(sub_args, 1, pygobject_new(G_OBJECT(args[i]))); + + py_args = PyTuple_New(3); + PyTuple_SetItem(py_args, 0, sub_args); + PyTuple_SetItem(py_args, 1, pygobject_new(G_OBJECT(ctx))); + PyTuple_SetItem(py_args, 2, pygobject_new(G_OBJECT(scope))); + + pyret = run_python_method(pyobj, "_call", py_args); + + if (pyret != NULL) + { + gobj_ret = pygobject_get(pyret); + + if (G_IS_OBJECT(gobj_ret)) + { + *out = gobj_ret; + + g_object_ref(G_OBJECT(*out)); + result = true; + + } + + Py_DECREF(pyret); + + } + + Py_DECREF(py_args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONNEXION AVEC L'API DE PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : self = élément d'appel à consulter. * +* args = arguments fournis pour l'opération. * +* * +* Description : Lance une résolution d'élément à appeler. * +* * +* Retour : Nouvel élément d'appel identifié ou None. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_registered_item_resolve(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + const char *target; /* Désignation de la cible */ + GScanContext *ctx; /* Contexte d'analyse */ + GScanScope *scope; /* Portée de variables locales */ + int ret; /* Bilan de lecture des args. */ + GScanRegisteredItem *item; /* Version native */ + bool status; /* Bilan d'exécution */ + GScanRegisteredItem *resolved; /* Elément trouvé */ + +#define SCAN_REGISTERED_ITEM_RESOLVE_METHOD PYTHON_METHOD_DEF \ +( \ + resolve, "$self, target, /, ctx=None, scope=None", \ + METH_VARARGS, py_scan_registered_item, \ + "Resolve a name into a scan item." \ + "\n" \ + "The *target* name is the only mandatory parameter and has to point"\ + " to only one item. The *ctx* argument points to an optional useful"\ + " storage for resolution lookup, as a" \ + " pychrysalide.analysis.scan.ScanContext instance. The *args* list" \ + " defines an optional list of arguments, as" \ + " pychrysalide.analysis.scan.ScanExpression instances, to use for" \ + " building the resolved item. The *final* flag states if the" \ + " scanning process is about to conclude or not." \ + "\n" \ + "The result is an object inheriting from" \ + " pychrysalide.analysis.scan.RegisteredItem or *None* if the" \ + " resolution operation failed." \ +) + + ctx = NULL; + scope = NULL; + + ret = PyArg_ParseTuple(args, "s|O&", &target, + convert_to_scan_context, &ctx); + if (!ret) return NULL; + + item = G_SCAN_REGISTERED_ITEM(pygobject_get(self)); + + status = g_scan_registered_item_resolve(item, target, ctx, scope, &resolved); + + if (!status) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("Unable to resolve any target from the item")); + } + else + { + if (resolved != NULL) + { + result = pygobject_new(G_OBJECT(resolved)); + g_object_unref(G_OBJECT(resolved)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un composant nommé à manipuler.* +* closure = non utilisé ici. * +* * +* Description : Fournit le désignation associée à un composant nommé. * +* * +* Retour : Description courante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_registered_item_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Décompte à retourner */ + GScanRegisteredItem *item; /* Version native */ + char *name; /* Désignation à convertir */ + +#define SCAN_REGISTERED_ITEM_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_scan_registered_item, \ + "Name linked to the registered item.\n" \ + "\n" \ + "The result should be a string, or *None* for the root namespace." \ +) + + item = G_SCAN_REGISTERED_ITEM(pygobject_get(self)); + + name = g_scan_registered_item_get_name(item); + + if (name == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + { + result = PyUnicode_FromString(name); + free(name); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_registered_item_type(void) +{ + static PyMethodDef py_scan_registered_item_methods[] = { + SCAN_REGISTERED_ITEM_RESOLVE_WRAPPER, + SCAN_REGISTERED_ITEM_REDUCE_WRAPPER, + SCAN_REGISTERED_ITEM_CALL_WRAPPER, + SCAN_REGISTERED_ITEM_RESOLVE_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_registered_item_getseters[] = { + SCAN_REGISTERED_ITEM_NAME_ATTRIB_WRAPPER, + SCAN_REGISTERED_ITEM_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_registered_item_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanRegisteredItem", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_IS_ABSTRACT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_REGISTERED_ITEM_DOC, + + .tp_methods = py_scan_registered_item_methods, + .tp_getset = py_scan_registered_item_getseters, + + .tp_init = py_scan_registered_item_init, + .tp_new = py_scan_registered_item_new, + + }; + + return &py_scan_registered_item_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...ScanRegisteredItem'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_registered_item_is_registered(void) +{ + PyTypeObject *type; /* Type 'ScanRegisteredItem' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_registered_item_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_REGISTERED_ITEM, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en expression d'évaluation généraliste. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_registered_item(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_registered_item_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to generic scan expression"); + break; + + case 1: + *((GScanRegisteredItem **)dst) = G_SCAN_REGISTERED_ITEM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/item.h b/plugins/pychrysalide/analysis/scan/item.h new file mode 100644 index 0000000..773908c --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/item.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * item.h - prototypes pour l'équivalent Python du fichier "analysis/scan/item.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_registered_item_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanRegisteredItem'. */ +bool ensure_python_scan_registered_item_is_registered(void); + +/* Tente de convertir en expression d'évaluation généraliste. */ +int convert_to_scan_registered_item(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_ITEM_H */ diff --git a/plugins/pychrysalide/analysis/scan/module.c b/plugins/pychrysalide/analysis/scan/module.c new file mode 100644 index 0000000..9ae0e52 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/module.c @@ -0,0 +1,125 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire scan en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "context.h" +#include "core.h" +#include "expr.h" +#include "item.h" +#include "options.h" +#include "scanner.h" +#include "space.h" +#include "exprs/module.h" +#include "patterns/module.h" +#include "../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.scan' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_module); + + result = (module != NULL); + + if (result) result = add_analysis_scan_exprs_module(module); + if (result) result = add_analysis_scan_patterns_module(module); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis.scan'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_content_scanner_is_registered(); + if (result) result = ensure_python_scan_context_is_registered(); + if (result) result = ensure_python_scan_expression_is_registered(); + if (result) result = ensure_python_scan_registered_item_is_registered(); + if (result) result = ensure_python_scan_options_is_registered(); + if (result) result = ensure_python_scan_namespace_is_registered(); + + if (result) result = populate_scan_module_with_core_methods(); + + if (result) result = populate_analysis_scan_exprs_module(); + if (result) result = populate_analysis_scan_patterns_module(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/module.h b/plugins/pychrysalide/analysis/scan/module.h new file mode 100644 index 0000000..a5e84b5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire scan en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan' à un module Python. */ +bool add_analysis_scan_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan'. */ +bool populate_analysis_scan_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/options.c b/plugins/pychrysalide/analysis/scan/options.c new file mode 100644 index 0000000..84c1784 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/options.c @@ -0,0 +1,511 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.c - équivalent Python du fichier "analysis/scan/options.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "options.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/options-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + + +CREATE_DYN_CONSTRUCTOR(scan_options, G_TYPE_SCAN_OPTIONS); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_options_init(PyObject *, PyObject *, PyObject *); + +/* Indique le type d'un moteur d'analyse de données sélectionné. */ +static PyObject *py_scan_options_get_backend_for_data(PyObject *, void *); + +/* Sélectionne un type de moteur d'analyse pour données brutes. */ +static int py_scan_options_set_backend_for_data(PyObject *, PyObject *, void *); + +/* Impose le format JSON comme type de sortie. */ +static PyObject *py_scan_options_get_print_json(PyObject *, void *); + +/* Mémorise le format JSON comme type de sortie. */ +static int py_scan_options_set_print_json(PyObject *, PyObject *, void *); + +/* Indique un besoin d'affichage des correspondances finales. */ +static PyObject *py_scan_options_get_print_strings(PyObject *, void *); + +/* Mémorise un besoin d'affichage des correspondances finales. */ +static int py_scan_options_set_print_strings(PyObject *, PyObject *, void *); + +/* Indique un besoin de statistiques en fin de compilation. */ +static PyObject *py_scan_options_get_print_stats(PyObject *, void *); + +/* Mémorise un besoin de statistiques en fin de compilation. */ +static int py_scan_options_set_print_stats(PyObject *, PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_OPTIONS_DOC \ + "The *ScanOptions* class stores all parameters used to tune" \ + " a scanning process.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanOptions()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique le type d'un moteur d'analyse de données sélectionné.* +* * +* Retour : Type d'objet, idéalement valide. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_backend_for_data(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + GType type; /* Type à transcrire */ + +#define SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + backend_for_data, py_scan_options, \ + "Type of the selected scan algorithm." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + type = g_scan_options_get_backend_for_data(options); + + result = pyg_type_wrapper_new(type); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Sélectionne un type de moteur d'analyse pour données brutes. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_backend_for_data(PyObject *self, PyObject *value, void *closure) +{ + GType type; /* Type à transcrit */ + GScanOptions *options; /* Version native */ + + type = pyg_type_from_object(value); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_backend_for_data(options, type); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Impose le format JSON comme type de sortie. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_json(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_JSON_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_json, py_scan_options, \ + "Define if the process summary is output into a JSON" \ + " format at the end of the scan or not." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_json(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise le format JSON comme type de sortie. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_json(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_json(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique un besoin d'affichage des correspondances finales. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_strings(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_STRINGS_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_strings, py_scan_options, \ + "Define if the matching patterns are printed with found" \ + " offset at the end of the scan or not." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_strings(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise un besoin d'affichage des correspondances finales. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_strings(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_strings(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format Axml. * +* closure = adresse non utilisée ici. * +* * +* Description : Indique un besoin de statistiques en fin de compilation. * +* * +* Retour : Etat de l'option visée à conservé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_options_get_print_stats(PyObject *self, void *closure) +{ + PyObject *result; /* Liste éventuelle à renvoyer */ + GScanOptions *options; /* Version native */ + bool state; /* Etat courant à consulter */ + +#define SCAN_OPTIONS_PRINT_STATS_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + print_stats, py_scan_options, \ + "Control the output of final statistics afer a scan." \ +) + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + state = g_scan_options_get_print_stats(options); + + result = state ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* value = valeur fournie à intégrer ou prendre en compte. * +* closure = adresse non utilisée ici. * +* * +* Description : Mémorise un besoin de statistiques en fin de compilation. * +* * +* Retour : Bilan de l'opération pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_options_set_print_stats(PyObject *self, PyObject *value, void *closure) +{ + bool state; /* Nouvel état à définir */ + GScanOptions *options; /* Version native */ + + if (value != Py_True && value != Py_False) + return -1; + + state = (value == Py_True); + + options = G_SCAN_OPTIONS(pygobject_get(self)); + + g_scan_options_set_print_stats(options, state); + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_options_type(void) +{ + static PyMethodDef py_scan_options_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_options_getseters[] = { + SCAN_OPTIONS_BACKEND_FOR_DATA_ATTRIB, + SCAN_OPTIONS_PRINT_JSON_ATTRIB, + SCAN_OPTIONS_PRINT_STRINGS_ATTRIB, + SCAN_OPTIONS_PRINT_STATS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_options_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanOptions", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = SCAN_OPTIONS_DOC, + + .tp_methods = py_scan_options_methods, + .tp_getset = py_scan_options_getseters, + + .tp_init = py_scan_options_init, + .tp_new = py_scan_options_new, + + }; + + return &py_scan_options_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanOptions'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_options_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanOptions' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_options_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_OPTIONS, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en ensemble d'options d'analyses. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_options(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_options_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan options"); + break; + + case 1: + *((GScanOptions **)dst) = G_SCAN_OPTIONS(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/options.h b/plugins/pychrysalide/analysis/scan/options.h new file mode 100644 index 0000000..3e83880 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/options.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * options.h - prototypes pour l'équivalent Python du fichier "analysis/scan/options.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_options_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanOptions'. */ +bool ensure_python_scan_options_is_registered(void); + +/* Tente de convertir en ensemble d'options d'analyses. */ +int convert_to_scan_options(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_OPTIONS_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am new file mode 100644 index 0000000..dd26fa5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/Makefile.am @@ -0,0 +1,22 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatterns.la + +libpychrysaanalysisscanpatterns_la_SOURCES = \ + backend.h backend.c \ + modifier.h modifier.c \ + module.h module.c + +libpychrysaanalysisscanpatterns_la_LIBADD = \ + backends/libpychrysaanalysisscanpatternsbackends.la \ + modifiers/libpychrysaanalysisscanpatternsmodifiers.la + +libpychrysaanalysisscanpatterns_la_CFLAGS = $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + $(TOOLKIT_CFLAGS) -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatterns_la_SOURCES:%c=) + + +SUBDIRS = backends modifiers diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.c b/plugins/pychrysalide/analysis/scan/patterns/backend.c new file mode 100644 index 0000000..03db143 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backend.c @@ -0,0 +1,202 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.c - équivalent Python du fichier "analysis/scan/backend.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "backend.h" + + +#include <pygobject.h> + + +#include <analysis/scan/patterns/backend-int.h> + + +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(engine_backend, G_TYPE_ENGINE_BACKEND, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_engine_backend_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_engine_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define ENGINE_BACKEND_DOC \ + "An *EngineBackend* object is the root class of all scan algorithm" \ + " looking for data patterns." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_engine_backend_type(void) +{ + static PyMethodDef py_engine_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_engine_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_engine_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.EngineBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = ENGINE_BACKEND_DOC, + + .tp_methods = py_engine_backend_methods, + .tp_getset = py_engine_backend_getseters, + + .tp_init = py_engine_backend_init, + .tp_new = py_engine_backend_new, + + }; + + return &py_engine_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....EngineBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_engine_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanNamespace' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_engine_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_ENGINE_BACKEND, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en méthode de recherches. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_engine_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_engine_backend_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to engine backend"); + break; + + case 1: + *((GEngineBackend **)dst) = G_ENGINE_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backend.h b/plugins/pychrysalide/analysis/scan/patterns/backend.h new file mode 100644 index 0000000..6b1f4cd --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backend.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * backend.h - prototypes pour l'équivalent Python du fichier "analysis/scan/backend.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_engine_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.EngineBackend'. */ +bool ensure_python_engine_backend_is_registered(void); + +/* Tente de convertir en méthode de recherches. */ +int convert_to_engine_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_BACKEND_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am new file mode 100644 index 0000000..cccfc2d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/Makefile.am @@ -0,0 +1,15 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsbackends.la + +libpychrysaanalysisscanpatternsbackends_la_SOURCES = \ + acism.h acism.c \ + bitap.h bitap.c \ + module.h module.c + +libpychrysaanalysisscanpatternsbackends_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatternsbackends_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c new file mode 100644 index 0000000..56d0b55 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.c - équivalent Python du fichier "analysis/scan/patterns/backends/acism.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "acism.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/backends/acism-int.h> + + +#include "../backend.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(acism_backend, G_TYPE_ACISM_BACKEND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_acism_backend_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_acism_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define ACISM_BACKEND_DOC \ + "A *AcismBackend* class provide an implementation of the Aho-Corasick" \ + " search algorithm with Interleaved State-transition Matrix (ACISM)." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " AcismBackend()" \ + "\n" \ + "See the relative white paper for more information:" \ + " https://docs.google.com/document/d/1e9Qbn22__togYgQ7PNyCz3YzIIVPKvrf8PCrFa74IFM" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_acism_backend_type(void) +{ + static PyMethodDef py_acism_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_acism_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_acism_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.backends.AcismBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = ACISM_BACKEND_DOC, + + .tp_methods = py_acism_backend_methods, + .tp_getset = py_acism_backend_getseters, + + .tp_init = py_acism_backend_init, + .tp_new = py_acism_backend_new, + + }; + + return &py_acism_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....AcismBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_acism_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'AcismBackend'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_acism_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_engine_backend_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ACISM_BACKEND, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en méthode de recherche ACISM. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_acism_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_acism_backend_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to ACISM backend"); + break; + + case 1: + *((GAcismBackend **)dst) = G_ACISM_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h new file mode 100644 index 0000000..9ed61fa --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/acism.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * acism.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/acism.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_acism_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.AcismBackend'. */ +bool ensure_python_acism_backend_is_registered(void); + +/* Tente de convertir en méthode de recherche ACISM. */ +int convert_to_acism_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_ACISM_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c new file mode 100644 index 0000000..c910f26 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.c @@ -0,0 +1,214 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.c - équivalent Python du fichier "analysis/scan/patterns/backends/bitap.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "bitap.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/backends/bitap-int.h> + + +#include "../backend.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(bitap_backend, G_TYPE_BITAP_BACKEND); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_bitap_backend_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_bitap_backend_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define BITAP_BACKEND_DOC \ + "A *BitapBackend* class provide an implementation of the Bitap" \ + " search algorithm." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " BitapBackend()" \ + "\n" \ + "See the relative white paper for more information:" \ + " https://en.wikipedia.org/wiki/Bitap_algorithm" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_bitap_backend_type(void) +{ + static PyMethodDef py_bitap_backend_methods[] = { + { NULL } + }; + + static PyGetSetDef py_bitap_backend_getseters[] = { + { NULL } + }; + + static PyTypeObject py_bitap_backend_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.backends.BitapBackend", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = BITAP_BACKEND_DOC, + + .tp_methods = py_bitap_backend_methods, + .tp_getset = py_bitap_backend_getseters, + + .tp_init = py_bitap_backend_init, + .tp_new = py_bitap_backend_new, + + }; + + return &py_bitap_backend_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....BitapBackend'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_bitap_backend_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'BitapBackend'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_bitap_backend_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.backends"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_engine_backend_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BITAP_BACKEND, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en méthode de recherche BITAP. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_bitap_backend(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_bitap_backend_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Bitap backend"); + break; + + case 1: + *((GBitapBackend **)dst) = G_BITAP_BACKEND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h new file mode 100644 index 0000000..f7853d4 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/bitap.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * bitap.h - prototypes pour l'équivalent Python du fichier "analysis/scan/patterns/backends/bitap.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_bitap_backend_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.backends.BitapBackend'. */ +bool ensure_python_bitap_backend_is_registered(void); + +/* Tente de convertir en méthode de recherche Bitap. */ +int convert_to_bitap_backend(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_BITAP_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.c b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c new file mode 100644 index 0000000..f4a0293 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.c @@ -0,0 +1,106 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire backends en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "acism.h" +#include "bitap.h" +#include "../../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.....backends' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_backends_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_backends_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns.backends", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_backends_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis....patterns.backends'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_backends_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_acism_backend_is_registered(); + if (result) result = ensure_python_bitap_backend_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/backends/module.h b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h new file mode 100644 index 0000000..ab1aad5 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/backends/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire backends en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns.backends' à un module Python. */ +bool add_analysis_scan_patterns_backends_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns.backends'. */ +bool populate_analysis_scan_patterns_backends_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_BACKENDS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.c b/plugins/pychrysalide/analysis/scan/patterns/modifier.c new file mode 100644 index 0000000..6547d91 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.c @@ -0,0 +1,416 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.c - équivalent Python du fichier "analysis/scan/modifier.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "modifier.h" + + +#include <pygobject.h> + + +#include <analysis/scan/patterns/modifier-int.h> + + +#include "../../../access.h" +#include "../../../helpers.h" + + + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(scan_token_modifier, G_TYPE_SCAN_TOKEN_MODIFIER, NULL); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_token_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_token_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_TOKEN_MODIFIER_DOC \ + "An *TokenModifier* object is the root class of all modifiers" \ + " for byte patterns." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = tampon de données à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Transforme une séquence d'octets pour motif de recherche. * +* * +* Retour : Liste des nouvelle(s) séquence(s) d'octets obtenue(s). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_token_modifier_transform(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + PyObject *py_src; /* Motifs Python en entrée */ + PyObject *py_arg; /* Eventuel paramètre de config*/ + sized_binary_t src; /* Entrée au format adapté */ + Py_ssize_t len; /* Quantité de ces données */ + int ret; /* Bilan de lecture des args. */ + sized_binary_t *src_list; /* Entrées au format adapté */ + size_t scount; /* Taille de cette liste */ + bool dyn_src; /* Allocation dynamique ? */ + Py_ssize_t size; /* Taille d'une séquence */ + Py_ssize_t k; /* Boucle de parcours #1 */ + PyObject *item; /* Elément de liste de motifs */ + modifier_arg_t arg; /* Eventuelle précision */ + GScanTokenModifier *modifier; /* Version native de l'instance*/ + sized_binary_t *dest; /* Liste des nouvelles chaînes */ + size_t dcount; /* Taille de cette liste */ + bool status; /* Bilan de l'opération */ + size_t i; /* Boucle de parcours #2 */ + +#define SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD PYTHON_METHOD_DEF \ +( \ + transform, "$self, data, /, arg", \ + METH_VARARGS, py_scan_token_modifier, \ + "Transform data from a byte pattern for an incoming scan.\n" \ + "\n" \ + "The data has to be provided as bytes.\n" \ + "\n" \ + "The method returns a tuple of transformed data as bytes, or" \ + " *None* in case of error." \ +) + + py_arg = NULL; + + ret = PyArg_ParseTuple(args, "O|O", &py_src, &py_arg); + if (!ret) return NULL; + + /* Constitution des motifs d'entrée */ + + if (PyBytes_Check(py_src)) + { + ret = PyBytes_AsStringAndSize(py_src, &src.data, &len); + if (ret == -1) return NULL; + + src.len = len; + + src_list = &src; + scount = 1; + + dyn_src = false; + + } + + else if (PySequence_Check(py_src)) + { + size = PySequence_Size(py_src); + + src_list = malloc(size * sizeof(sized_binary_t)); + scount = size; + + dyn_src = true; + + for (k = 0; k < size; k++) + { + item = PySequence_ITEM(py_src, k); + + if (PyBytes_Check(item)) + { + ret = PyBytes_AsStringAndSize(item, &src_list[k].data, &len); + if (ret == -1) return NULL; + + src_list[k].len = len; + + } + else + { + free(src_list); + + PyErr_SetString(PyExc_TypeError, "lists of items other than bytes are not supported"); + return NULL; + } + + } + + } + + else + { + PyErr_SetString(PyExc_TypeError, "only bytes and lists of bytes are expected as input for modifiers"); + return NULL; + } + + /* Récupération d'une éventuelle précision opérationnelle */ + + if (py_arg != NULL) + { + if (PyLong_Check(py_arg)) + { + arg.type = MAT_UNSIGNED_INTEGER; + arg.value.u_integer = PyLong_AsUnsignedLongLong(py_arg); + } + + else + { + if (dyn_src) + free(src_list); + + PyErr_SetString(PyExc_TypeError, "unable to handle the argument type for calling a modifier"); + return NULL; + + } + + } + + /* Création des nouveaux motifs */ + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self)); + + if (py_arg == NULL) + status = g_scan_token_modifier_transform(modifier, src_list, scount, &dest, &dcount); + else + status = g_scan_token_modifier_transform_with_arg(modifier, src_list, scount, &arg, &dest, &dcount); + + if (dyn_src) + free(src_list); + + if (status) + { + result = PyTuple_New(dcount); + + for (i = 0; i < dcount; i++) + { + PyTuple_SetItem(result, i, PyBytes_FromStringAndSize(dest[i].data, dest[i].len)); + exit_szstr(&dest[i]); + } + + free(dest); + + } + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un composant nommé à manipuler.* +* closure = non utilisé ici. * +* * +* Description : Fournit le désignation associée à un composant nommé. * +* * +* Retour : Description courante. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_token_modifier_get_name(PyObject *self, void *closure) +{ + PyObject *result; /* Décompte à retourner */ + GScanTokenModifier *modifier; /* Version native */ + char *name; /* Désignation à convertir */ + +#define SCAN_TOKEN_MODIFIER_NAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + name, py_scan_token_modifier, \ + "Call name for the modifier.\n" \ + "\n" \ + "The result is a string." \ +) + + modifier = G_SCAN_TOKEN_MODIFIER(pygobject_get(self)); + + name = g_scan_token_modifier_get_name(modifier); + + if (name == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + { + result = PyUnicode_FromString(name); + free(name); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_token_modifier_type(void) +{ + static PyMethodDef py_scan_token_modifier_methods[] = { + SCAN_TOKEN_MODIFIER_TRANSFORM_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_token_modifier_getseters[] = { + SCAN_TOKEN_MODIFIER_NAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_token_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.TokenModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_TOKEN_MODIFIER_DOC, + + .tp_methods = py_scan_token_modifier_methods, + .tp_getset = py_scan_token_modifier_getseters, + + .tp_init = py_scan_token_modifier_init, + .tp_new = py_scan_token_modifier_new, + + }; + + return &py_scan_token_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....TokenModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_token_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'TokenModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_token_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_TOKEN_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation de séquence d'octets. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_token_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_token_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to token modifier"); + break; + + case 1: + *((GScanTokenModifier **)dst) = G_SCAN_TOKEN_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifier.h b/plugins/pychrysalide/analysis/scan/patterns/modifier.h new file mode 100644 index 0000000..770b2c1 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifier.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * modifier.h - prototypes pour l'équivalent Python du fichier "analysis/scan/modifier.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_token_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.TokenModifier'. */ +bool ensure_python_scan_token_modifier_is_registered(void); + +/* Tente de convertir en transformation de séquence d'octets. */ +int convert_to_scan_token_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_MODIFIER_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am new file mode 100644 index 0000000..ae53e45 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/Makefile.am @@ -0,0 +1,18 @@ + +noinst_LTLIBRARIES = libpychrysaanalysisscanpatternsmodifiers.la + +libpychrysaanalysisscanpatternsmodifiers_la_SOURCES = \ + hex.h hex.c \ + list.h list.c \ + module.h module.c \ + plain.h plain.c \ + rev.h rev.c \ + xor.h xor.c + +libpychrysaanalysisscanpatternsmodifiers_la_CFLAGS = $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) $(TOOLKIT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT + + +devdir = $(includedir)/chrysalide/$(subdir) + +dev_HEADERS = $(libpychrysaanalysisscanpatternsmodifiers_la_SOURCES:%c=) diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c new file mode 100644 index 0000000..503580d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "hex.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/hex.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_hex_modifier, G_TYPE_SCAN_HEX_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_hex_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_hex_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_HEX_MODIFIER_DOC \ + "The *HexModifier* class transforms a byte pattern into its" \ + " corresponding byte sequence in lower case." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " HexModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_hex_modifier_type(void) +{ + static PyMethodDef py_scan_hex_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_hex_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_hex_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.HexModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_HEX_MODIFIER_DOC, + + .tp_methods = py_scan_hex_modifier_methods, + .tp_getset = py_scan_hex_modifier_getseters, + + .tp_init = py_scan_hex_modifier_init, + .tp_new = py_scan_hex_modifier_new, + + }; + + return &py_scan_hex_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....HexModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_hex_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'HexModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_hex_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_HEX_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_hex_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_hex_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to hex modifier"); + break; + + case 1: + *((GScanHexModifier **)dst) = G_SCAN_HEX_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h new file mode 100644 index 0000000..5d70a01 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/hex.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_hex_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.HexModifier'. */ +bool ensure_python_scan_hex_modifier_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_hex_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_HEX_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c new file mode 100644 index 0000000..7c77d63 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.c @@ -0,0 +1,320 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "list.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/list.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_modifier_list, G_TYPE_SCAN_MODIFIER_LIST); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_modifier_list_init(PyObject *, PyObject *, PyObject *); + +/* Intègre un nouveau transformateur dans une liste. */ +static PyObject *py_scan_modifier_list_add(PyObject *, PyObject *); + +/* Fournit les transformateurs associés à la liste. */ +static PyObject *py_scan_modifier_list_get_modifiers(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_modifier_list_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_MODIFIER_LIST_DOC \ + "The *ModifierList* class is a special modifier which groups a list of" \ + " modifiers for byte patterns." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ModifierList()" \ + "\n" \ + "The keyword for such a modifier is *(list)*." + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = projet d'étude à manipuler. * +* args = arguments accompagnant l'appel. * +* * +* Description : Intègre un nouveau transformateur dans une liste. * +* * +* Retour : Bilan de l'ajout : False si un élément similaire est déjà là.* +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_modifier_list_add(PyObject *self, PyObject *args) +{ + PyObject *result; /* Absence de retour Python */ + GScanTokenModifier *modifier; /* Modificateur à intégrer */ + int ret; /* Bilan de lecture des args. */ + GScanModifierList *list; /* Version GLib du type */ + bool status; /* Bilan de l'opération */ + +#define SCAN_MODIFIER_LIST_ADD_METHOD PYTHON_METHOD_DEF \ +( \ + add, "$self, modifier, /", \ + METH_VARARGS, py_scan_modifier_list, \ + "Add an extra modifier to the list.\n" \ + "\n" \ + "This *modifier* parameter has to be a" \ + " pychrysalide.analysis.scan.patterns.TokenModifier instance." \ + "\n" \ + "The function returns *True* if the provided modifier did not already" \ + " exist in the list, *False* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_token_modifier, &modifier); + if (!ret) return NULL; + + list = G_SCAN_MODIFIER_LIST(pygobject_get(self)); + + status = g_scan_modifier_list_add(list, modifier); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit les transformateurs associés à la liste. * +* * +* Retour : Liste de modificateurs de séquence d'octets. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_modifier_list_get_modifiers(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GScanModifierList *list; /* Version GLib du type */ + size_t count; /* Nombre de transformateurs */ + size_t i; /* Boucle de parcours */ + GScanTokenModifier *modifier; /* Modificateur de la liste */ + +#define SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + modifiers, py_scan_modifier_list, \ + "List of all modifiers contained in a list.\n" \ + "\n" \ + "The returned value is a tuple of pychrysalide.analysis.scan.patterns.TokenModifier" \ + " instances." \ +) + + list = G_SCAN_MODIFIER_LIST(pygobject_get(self)); + + count = g_scan_modifier_list_count(list); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + modifier = g_scan_modifier_list_get(list, i); + + PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(modifier))); + + g_object_unref(modifier); + + } + + return result; + +} + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_modifier_list_type(void) +{ + static PyMethodDef py_scan_modifier_list_methods[] = { + SCAN_MODIFIER_LIST_ADD_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_modifier_list_getseters[] = { + SCAN_MODIFIER_LIST_MODIFIERS_ATTRIB, + { NULL } + }; + + static PyTypeObject py_scan_modifier_list_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ModifierList", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_MODIFIER_LIST_DOC, + + .tp_methods = py_scan_modifier_list_methods, + .tp_getset = py_scan_modifier_list_getseters, + + .tp_init = py_scan_modifier_list_init, + .tp_new = py_scan_modifier_list_new, + + }; + + return &py_scan_modifier_list_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....ModifierList'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_modifier_list_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ModifierList' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_modifier_list_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_MODIFIER_LIST, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en liste de transormations d'octets. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_modifier_list(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_modifier_list_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to modifier list"); + break; + + case 1: + *((GScanModifierList **)dst) = G_SCAN_MODIFIER_LIST(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h new file mode 100644 index 0000000..133de8d --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/list.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * list.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/list.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_modifier_list_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ModifierList'. */ +bool ensure_python_scan_modifier_list_is_registered(void); + +/* Tente de convertir en liste de transormations d'octets. */ +int convert_to_scan_modifier_list(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_LIST_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c new file mode 100644 index 0000000..ae450dc --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.c @@ -0,0 +1,112 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire modifiers en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "hex.h" +#include "list.h" +#include "plain.h" +#include "rev.h" +#include "xor.h" +#include "../../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis....modifiers' à un module Python. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_modifiers_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_modifiers_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns.modifiers", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_modifiers_module); + + result = (module != NULL); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis...patterns.modifiers'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_modifiers_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_scan_hex_modifier_is_registered(); + if (result) result = ensure_python_scan_modifier_list_is_registered(); + if (result) result = ensure_python_scan_plain_modifier_is_registered(); + if (result) result = ensure_python_scan_reverse_modifier_is_registered(); + if (result) result = ensure_python_scan_xor_modifier_is_registered(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h new file mode 100644 index 0000000..8094efc --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire modifiers en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns.modifiers' à un module Python. */ +bool add_analysis_scan_patterns_modifiers_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns.modifiers'. */ +bool populate_analysis_scan_patterns_modifiers_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c new file mode 100644 index 0000000..7a260c1 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "plain.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/plain.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_plain_modifier, G_TYPE_SCAN_PLAIN_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_plain_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_plain_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_PLAIN_MODIFIER_DOC \ + "The *PlainModifier* class provide an transmision of a byte pattern" \ + " without any modification." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " PlainModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_plain_modifier_type(void) +{ + static PyMethodDef py_scan_plain_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_plain_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_plain_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.PlainModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_PLAIN_MODIFIER_DOC, + + .tp_methods = py_scan_plain_modifier_methods, + .tp_getset = py_scan_plain_modifier_getseters, + + .tp_init = py_scan_plain_modifier_init, + .tp_new = py_scan_plain_modifier_new, + + }; + + return &py_scan_plain_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....PlainModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_plain_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'PlainModifier' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_plain_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_PLAIN_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transmission d'octets à l'identique. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_plain_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_plain_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to plain modifier"); + break; + + case 1: + *((GScanPlainModifier **)dst) = G_SCAN_PLAIN_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h new file mode 100644 index 0000000..03949d8 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/plain.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * plain.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/plain.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_plain_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.PlainModifier'. */ +bool ensure_python_scan_plain_modifier_is_registered(void); + +/* Tente de convertir en transmission d'octets à l'identique. */ +int convert_to_scan_plain_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_PLAIN_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c new file mode 100644 index 0000000..841e929 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.c @@ -0,0 +1,211 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * hex.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/hex.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "rev.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/rev.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_reverse_modifier, G_TYPE_SCAN_REVERSE_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_reverse_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_reverse_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_HEX_MODIFIER_DOC \ + "The *ReverseModifier* class transforms a byte pattern by reversing" \ + " the order of each bytes." \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ReverseModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_reverse_modifier_type(void) +{ + static PyMethodDef py_scan_reverse_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_reverse_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_reverse_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_HEX_MODIFIER_DOC, + + .tp_methods = py_scan_reverse_modifier_methods, + .tp_getset = py_scan_reverse_modifier_getseters, + + .tp_init = py_scan_reverse_modifier_init, + .tp_new = py_scan_reverse_modifier_new, + + }; + + return &py_scan_reverse_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....ReverseModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_reverse_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python ReverseModifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_reverse_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_REVERSE_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation d'octets par inverse. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_reverse_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_reverse_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to reverse modifier"); + break; + + case 1: + *((GScanReverseModifier **)dst) = G_SCAN_REVERSE_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h new file mode 100644 index 0000000..fe10e1e --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/rev.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * rev.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/rev.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_reverse_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.ReverseModifier'. */ +bool ensure_python_scan_reverse_modifier_is_registered(void); + +/* Tente de convertir en transformation d'octets par inverse. */ +int convert_to_scan_reverse_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_REV_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c new file mode 100644 index 0000000..17a32f4 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.c @@ -0,0 +1,210 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * xor.c - équivalent Python du fichier "analysis/scan/patterns/modifiers/xor.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "xor.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/scan/patterns/modifiers/xor.h> + + +#include "../modifier.h" +#include "../../../../access.h" +#include "../../../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_xor_modifier, G_TYPE_SCAN_XOR_MODIFIER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_xor_modifier_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_xor_modifier_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SCAN_XOR_MODIFIER_DOC \ + "The *XorModifier* class transforms a byte pattern by XORing bytes.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " XorModifier()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_xor_modifier_type(void) +{ + static PyMethodDef py_scan_xor_modifier_methods[] = { + { NULL } + }; + + static PyGetSetDef py_scan_xor_modifier_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_xor_modifier_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.patterns.modifiers.XorModifier", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_XOR_MODIFIER_DOC, + + .tp_methods = py_scan_xor_modifier_methods, + .tp_getset = py_scan_xor_modifier_getseters, + + .tp_init = py_scan_xor_modifier_init, + .tp_new = py_scan_xor_modifier_new, + + }; + + return &py_scan_xor_modifier_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....XorModifier'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_xor_modifier_is_registered(void) +{ + PyTypeObject *type; /* Type Python XorModifier */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_xor_modifier_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan.patterns.modifiers"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_scan_token_modifier_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_XOR_MODIFIER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en transformation d'octets par inverse. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_xor_modifier(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_xor_modifier_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to XOR modifier"); + break; + + case 1: + *((GScanXorModifier **)dst) = G_SCAN_XOR_MODIFIER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h new file mode 100644 index 0000000..7b9bb69 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/modifiers/xor.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * xor.h - équivalent Python du fichier "analysis/scan/patterns/modifiers/xor.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_xor_modifier_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.patterns.modifiers.XorModifier'. */ +bool ensure_python_scan_xor_modifier_is_registered(void); + +/* Tente de convertir en transformation d'octets par inverse. */ +int convert_to_scan_xor_modifier(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODIFIERS_XOR_H */ diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.c b/plugins/pychrysalide/analysis/scan/patterns/module.c new file mode 100644 index 0000000..123b23a --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/module.c @@ -0,0 +1,114 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire patterns en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "module.h" + + +#include <assert.h> + + +#include "backend.h" +#include "modifier.h" +#include "backends/module.h" +#include "modifiers/module.h" +#include "../../../helpers.h" + + + +/****************************************************************************** +* * +* Paramètres : super = module dont la définition est à compléter. * +* * +* Description : Ajoute le module 'analysis.scan.patterns' à un module Python.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_analysis_scan_patterns_module(PyObject *super) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC \ + "This module provide all the features useful for scanning" \ + " binary contents." + + static PyModuleDef py_chrysalide_analysis_scan_patterns_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.analysis.scan.patterns", + .m_doc = PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_DOC, + + .m_size = -1, + + }; + + module = build_python_module(super, &py_chrysalide_analysis_scan_patterns_module); + + result = (module != NULL); + + if (result) result = add_analysis_scan_patterns_backends_module(module); + if (result) result = add_analysis_scan_patterns_modifiers_module(module); + + if (!result) + Py_XDECREF(module); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'analysis.scan.patterns'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_analysis_scan_patterns_module(void) +{ + bool result; /* Bilan à retourner */ + + result = true; + + if (result) result = ensure_python_engine_backend_is_registered(); + if (result) result = ensure_python_scan_token_modifier_is_registered(); + + if (result) result = populate_analysis_scan_patterns_backends_module(); + if (result) result = populate_analysis_scan_patterns_modifiers_module(); + + assert(result); + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/patterns/module.h b/plugins/pychrysalide/analysis/scan/patterns/module.h new file mode 100644 index 0000000..bc25129 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/patterns/module.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire patterns en tant que module + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Ajoute le module 'analysis.scan.patterns' à un module Python. */ +bool add_analysis_scan_patterns_module(PyObject *); + +/* Intègre les objets du module 'analysis.scan.patterns'. */ +bool populate_analysis_scan_patterns_module(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_PATTERNS_MODULE_H */ diff --git a/plugins/pychrysalide/analysis/scan/scanner.c b/plugins/pychrysalide/analysis/scan/scanner.c new file mode 100644 index 0000000..bc58c9a --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/scanner.c @@ -0,0 +1,487 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.c - équivalent Python du fichier "analysis/scan/scanner.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "scanner.h" + + +#include <malloc.h> +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/context.h> +#include <analysis/scan/scanner-int.h> + + +#include "context.h" +#include "options.h" +#include "../content.h" +#include "../../access.h" +#include "../../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(content_scanner, G_TYPE_CONTENT_SCANNER); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_content_scanner_init(PyObject *, PyObject *, PyObject *); + +/* Lance une analyse d'un contenu binaire. */ +static PyObject *py_content_scanner_analyze(PyObject *, PyObject *); + +/* Convertit un gestionnaire de recherches en JSON. */ +static PyObject *py_content_scanner_convert_to_json(PyObject *, PyObject *); + +/* Indique le chemin d'un éventuel fichier de source. */ +static PyObject *py_content_scanner_get_filename(PyObject *, void *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_content_scanner_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *text; /* Contenu de règles à traiter */ + Py_ssize_t len; /* Taille de ce nom */ + const char *filename; /* Fichier de définitions */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Création GLib à transmettre */ + + static char *kwlist[] = { "text", "filename", NULL }; + +#define CONTENT_SCANNER_DOC \ + "A ContentScanner object provides support for rules processing" \ + " against binary contents.\n" \ + "\n" \ + "Instances can be created using one of the following" \ + " constructors:\n" \ + "\n" \ + " ContentScanner(text=str)" \ + "\n" \ + " ContentScanner(filename=str)" \ + "\n" \ + "Where *text* is a string for the rules definitions and" \ + " *filename* an alternative string for a path pointing to a" \ + " definition file." + + /* Récupération des paramètres */ + + text = NULL; + len = 0; + filename = NULL; + + ret = PyArg_ParseTupleAndKeywords(args, kwds, "|s#s", kwlist, &text, &len, &filename); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + if (text != NULL) + { + if (!g_content_scanner_create_from_text(scanner, text, len)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner.")); + return -1; + } + + } + + else if (filename != NULL) + { + if (!g_content_scanner_create_from_file(scanner, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create content scanner.")); + return -1; + } + + } + + else + { + PyErr_SetString(PyExc_ValueError, _("Unable to create empty content scanner.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Lance une analyse d'un contenu binaire. * +* * +* Retour : Contexte de suivi pour l'analyse menée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_analyze(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanOptions *options; /* Paramètres d'analyse */ + GBinContent *content; /* Contenu binaire à traiter */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Encadrement de recherche */ + GScanContext *context; /* Contexte de suivi */ + +#define CONTENT_SCANNER_ANALYZE_METHOD PYTHON_METHOD_DEF \ +( \ + analyze, "$self, options, content, /", \ + METH_VARARGS, py_content_scanner, \ + "Run a scan against a binary content.\n" \ + "\n" \ + "The *content* argument is a pychrysalide.analysis.BinContent" \ + " object pointing to data to analyze.\n" \ + "\n" \ + "The method returns a pychrysalide.analysis.scan.ScanContext" \ + " object tracking all the scan results." \ +) + + ret = PyArg_ParseTuple(args, "O&O&", convert_to_scan_options, &options, convert_to_binary_content, &content); + if (!ret) return NULL; + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + context = g_content_scanner_analyze(scanner, options, content); + + result = pygobject_new(G_OBJECT(context)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Convertit un gestionnaire de recherches en texte. * +* * +* Retour : Données textuelles ou None en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_convert_to_text(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanContext *context; /* Contexte d'analyse */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Encadrement de recherche */ + char *out; /* Données en sortie */ + +#define CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD PYTHON_METHOD_DEF \ +( \ + convert_to_text, "$self, context, /", \ + METH_VARARGS, py_content_scanner, \ + "Output a scan results as text.\n" \ + "\n" \ + "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \ + " instance provided by a previous call to *self.analyze()*. This" \ + " context stores all the scan results.\n" \ + "\n" \ + "The method returns a string value, or *None* in case of failure." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context); + if (!ret) return NULL; + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + out = g_content_scanner_convert_to_text(scanner, context); + + if (out != NULL) + { + result = PyUnicode_FromString(out); + free(out); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant un format. * +* args = arguments fournis à l'appel. * +* * +* Description : Convertit un gestionnaire de recherches en JSON. * +* * +* Retour : Données textuelles au format JSON ou None en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_convert_to_json(PyObject *self, PyObject *args) +{ + PyObject *result; /* Contexte de suivi à renvoyer*/ + GScanContext *context; /* Contexte d'analyse */ + int ret; /* Bilan de lecture des args. */ + GContentScanner *scanner; /* Encadrement de recherche */ + char *out; /* Données en sortie */ + +#define CONTENT_SCANNER_CONVERT_TO_JSON_METHOD PYTHON_METHOD_DEF \ +( \ + convert_to_json, "$self, context, /", \ + METH_VARARGS, py_content_scanner, \ + "Output a scan results as JSON data.\n" \ + "\n" \ + "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \ + " instance provided by a previous call to *self.analyze()*. This" \ + " context stores all the scan results.\n" \ + "\n" \ + "The method returns JSON data as a string value, or *None* in case" \ + " of failure." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context); + if (!ret) return NULL; + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + out = g_content_scanner_convert_to_json(scanner, context); + + if (out != NULL) + { + result = PyUnicode_FromString(out); + free(out); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le chemin d'un éventuel fichier de source. * +* * +* Retour : Chemin d'un éventuel fichier de définitions ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_content_scanner_get_filename(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GContentScanner *scanner; /* Analyseur à consulter */ + const char *filename; /* Chemin d'accès à transmettre*/ + +#define CONTENT_SCANNER_FILENAME_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + filename, py_content_scanner, \ + "Provide the access path to the source file of the rules'" \ + " definition, or *None* if these rules have not been loaded"\ + " from memory." \ +) + + scanner = G_CONTENT_SCANNER(pygobject_get(self)); + + filename = g_content_scanner_get_filename(scanner); + + if (filename != NULL) + result = PyUnicode_FromString(filename); + + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_content_scanner_type(void) +{ + static PyMethodDef py_content_scanner_methods[] = { + CONTENT_SCANNER_ANALYZE_METHOD, + CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD, + CONTENT_SCANNER_CONVERT_TO_JSON_METHOD, + { NULL } + }; + + static PyGetSetDef py_content_scanner_getseters[] = { + CONTENT_SCANNER_FILENAME_ATTRIB, + { NULL } + }; + + static PyTypeObject py_content_scanner_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ContentScanner", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = CONTENT_SCANNER_DOC, + + .tp_methods = py_content_scanner_methods, + .tp_getset = py_content_scanner_getseters, + + .tp_init = py_content_scanner_init, + .tp_new = py_content_scanner_new, + + }; + + return &py_content_scanner_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ContentScanner. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_content_scanner_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ContentScanner'*/ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_content_scanner_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_CONTENT_SCANNER, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en scanner de contenus binaires. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_content_scanner(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_content_scanner_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to content scanner"); + break; + + case 1: + *((GContentScanner **)dst) = G_CONTENT_SCANNER(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/scanner.h b/plugins/pychrysalide/analysis/scan/scanner.h new file mode 100644 index 0000000..b3b1baf --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/scanner.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * scanner.h - prototypes pour l'équivalent Python du fichier "analysis/scan/scanner.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_content_scanner_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ContentScanner'. */ +bool ensure_python_content_scanner_is_registered(void); + +/* Tente de convertir en scanner de contenus binaires. */ +int convert_to_content_scanner(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SCANNER_H */ diff --git a/plugins/pychrysalide/analysis/scan/space.c b/plugins/pychrysalide/analysis/scan/space.c new file mode 100644 index 0000000..6ea87b8 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/space.c @@ -0,0 +1,283 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.c - équivalent Python du fichier "analysis/scan/space.c" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "space.h" + + +#include <pygobject.h> + + +#include <i18n.h> +#include <analysis/content.h> +#include <analysis/scan/item.h> +#include <analysis/scan/space-int.h> +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> +#include <plugins/pychrysalide/analysis/content.h> + + +#include "item.h" + + + +CREATE_DYN_CONSTRUCTOR(scan_namespace, G_TYPE_SCAN_NAMESPACE); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_scan_namespace_init(PyObject *, PyObject *, PyObject *); + +/* Intègre un nouvel élément dans l'esapce de noms. */ +static PyObject *py_scan_namespace_register_item(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_scan_namespace_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + const char *name; /* Désignation de l'espace */ + int ret; /* Bilan de lecture des args. */ + GScanNamespace *space; /* Création GLib à transmettre */ + +#define SCAN_NAMESPACE_DOC \ + "ScanNamespace defines a group of properties and functions for a" \ + " given scan theme.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " ScanNamespace(name)" \ + "\n" \ + "Where *name* is a string providing the name of the new namespace." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, "s", &name); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Elément de base */ + + space = G_SCAN_NAMESPACE(pygobject_get(self)); + + if (!g_scan_namespace_create(space, name)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create scan namespace.")); + return -1; + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet représentant une table de chaînes. * +* args = arguments fournis pour l'opération. * +* * +* Description : Intègre un nouvel élément dans l'esapce de noms. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_scan_namespace_register_item(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GScanRegisteredItem *item; /* Elément d'évaluation à lier */ + int ret; /* Bilan de lecture des args. */ + GScanNamespace *space; /* Version native */ + bool status; /* Bilan de l'opération */ + +#define SCAN_NAMESPACE_REGISTER_ITEM_METHOD PYTHON_METHOD_DEF \ +( \ + register_item, "$self, item, /", \ + METH_VARARGS, py_scan_namespace, \ + "Include an item into a namespace.\n" \ + "\n" \ + "The *item* argument has to be a pychrysalide.analysis.scan.RegisteredItem" \ + " instance.\n" \ + "\n" \ + "The function returns a boolean value translating the operation status:" \ + " *True* in case of success, *False* for a failure.\n" \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_scan_registered_item, &item); + if (!ret) return NULL; + + space = G_SCAN_NAMESPACE(pygobject_get(self)); + + status = g_scan_namespace_register_item(space, item); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_scan_namespace_type(void) +{ + static PyMethodDef py_scan_namespace_methods[] = { + SCAN_NAMESPACE_REGISTER_ITEM_METHOD, + { NULL } + }; + + static PyGetSetDef py_scan_namespace_getseters[] = { + { NULL } + }; + + static PyTypeObject py_scan_namespace_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.analysis.scan.ScanNamespace", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SCAN_NAMESPACE_DOC, + + .tp_methods = py_scan_namespace_methods, + .tp_getset = py_scan_namespace_getseters, + + .tp_init = py_scan_namespace_init, + .tp_new = py_scan_namespace_new, + + }; + + return &py_scan_namespace_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide...scan.ScanNamespace'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_scan_namespace_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ScanNamespace' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_scan_namespace_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.analysis.scan"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SCAN_NAMESPACE, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en espace de noms pour scan. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_scan_namespace(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_scan_namespace_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to scan namespace"); + break; + + case 1: + *((GScanNamespace **)dst) = G_SCAN_NAMESPACE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/analysis/scan/space.h b/plugins/pychrysalide/analysis/scan/space.h new file mode 100644 index 0000000..0166c04 --- /dev/null +++ b/plugins/pychrysalide/analysis/scan/space.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * space.h - prototypes pour l'équivalent Python du fichier "analysis/scan/space.h" + * + * Copyright (C) 2022 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H +#define _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_scan_namespace_type(void); + +/* Prend en charge l'objet 'pychrysalide.analysis.scan.ScanNamespace'. */ +bool ensure_python_scan_namespace_is_registered(void); + +/* Tente de convertir en espace de noms pour scan. */ +int convert_to_scan_namespace(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ANALYSIS_SCAN_SPACE_H */ diff --git a/plugins/pychrysalide/analysis/storage/Makefile.am b/plugins/pychrysalide/analysis/storage/Makefile.am index 01240cb..d0a4df4 100644 --- a/plugins/pychrysalide/analysis/storage/Makefile.am +++ b/plugins/pychrysalide/analysis/storage/Makefile.am @@ -9,19 +9,10 @@ libpychrysaanalysisstorage_la_SOURCES = \ storage.h storage.c \ tpmem.h tpmem.c -libpychrysaanalysisstorage_la_LIBADD = - -libpychrysaanalysisstorage_la_LDFLAGS = +libpychrysaanalysisstorage_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysisstorage_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/analysis/storage/cache.c b/plugins/pychrysalide/analysis/storage/cache.c index 9859623..8cd5bac 100644 --- a/plugins/pychrysalide/analysis/storage/cache.c +++ b/plugins/pychrysalide/analysis/storage/cache.c @@ -100,7 +100,7 @@ static PyObject *py_object_cache_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -304,7 +304,7 @@ bool ensure_python_object_cache_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_CACHE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_CACHE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/storage/serialize.c b/plugins/pychrysalide/analysis/storage/serialize.c index 6e1dd41..40fcef7 100644 --- a/plugins/pychrysalide/analysis/storage/serialize.c +++ b/plugins/pychrysalide/analysis/storage/serialize.c @@ -45,10 +45,10 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *, gpointer *); /* Charge un objet depuis une mémoire tampon. */ -static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, packed_buffer *); +static bool py_serializable_object_load_wrapper(GSerializableObject *, GObjectStorage *, packed_buffer_t *); /* Sauvegarde un objet dans une mémoire tampon. */ -static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, packed_buffer *); +static bool py_serializable_object_store_wrapper(const GSerializableObject *, GObjectStorage *, packed_buffer_t *); @@ -117,7 +117,7 @@ static void py_serializable_object_interface_init(GSerializableObjectIface *ifac * * ******************************************************************************/ -static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, packed_buffer *pbuf) +static bool py_serializable_object_load_wrapper(GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ @@ -193,7 +193,7 @@ static bool py_serializable_object_load_wrapper(GSerializableObject *object, GOb * * ******************************************************************************/ -static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, packed_buffer *pbuf) +static bool py_serializable_object_store_wrapper(const GSerializableObject *object, GObjectStorage *storage, packed_buffer_t *pbuf) { bool result; /* Bilan à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ @@ -278,7 +278,7 @@ static bool py_serializable_object_load(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ GObjectStorage *storage; /* Conservateur à manipuler */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ GSerializableObject *object; /* Version native */ bool status; /* Bilan de l'opération */ @@ -330,7 +330,7 @@ static bool py_serializable_object_store(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ GObjectStorage *storage; /* Conservateur à manipuler */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ GSerializableObject *object; /* Version native */ bool status; /* Bilan de l'opération */ diff --git a/plugins/pychrysalide/analysis/storage/storage.c b/plugins/pychrysalide/analysis/storage/storage.c index 1ebcc62..c54fe0f 100644 --- a/plugins/pychrysalide/analysis/storage/storage.c +++ b/plugins/pychrysalide/analysis/storage/storage.c @@ -33,7 +33,6 @@ #include "serialize.h" -#include "../loaded.h" #include "../../access.h" #include "../../helpers.h" #include "../../common/packed.h" @@ -54,8 +53,11 @@ static int py_object_storage_init(PyObject *, PyObject *, PyObject *); /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ -/* Ajoute le support d'un nouveau groupe d'objets construits. */ -static PyObject *py_object_storage_add_backend(PyObject *, PyObject *); +/* Charge le support d'une conservation d'objets en place. */ +static PyObject *py_object_storage_load(PyObject *, PyObject *); + +/* Sauvegarde le support d'une conservation d'objets en place. */ +static PyObject *py_object_storage_store(PyObject *, PyObject *); /* Charge un objet à partir de données rassemblées. */ static PyObject *py_object_storage_load_object(PyObject *, PyObject *); @@ -113,7 +115,7 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -152,7 +154,7 @@ static PyObject *py_object_storage_new(PyTypeObject *type, PyObject *args, PyObj static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds) { - GLoadedContent *loaded; /* Contenu chargé et traité */ + const char *hash; /* Empreinte de contenu */ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ @@ -162,14 +164,14 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " ObjectStorage(loaded)" \ + " ObjectStorage(hash)" \ "\n" \ - "Where *loaded* is a pychrysalide.analysis.LoadedContent instance" \ - " linked to the objects which can apply for a storage process." + "Where *hash* should a string built from the checksum of the" \ + " relative binary content linked to the storage.pychrysalide." /* Récupération des paramètres */ - ret = PyArg_ParseTuple(args, "O&", convert_to_loaded_content, &loaded); + ret = PyArg_ParseTuple(args, "s", &hash); if (!ret) return -1; /* Initialisation d'un objet GLib */ @@ -181,8 +183,7 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds storage = G_OBJECT_STORAGE(pygobject_get(self)); - storage->loaded = loaded; - g_object_ref(G_OBJECT(loaded)); + storage->hash = strdup(hash); return 0; @@ -200,7 +201,61 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds * Paramètres : self = classe représentant une mémorisation de types. * * args = arguments fournis à l'appel. * * * -* Description : Ajoute le support d'un nouveau groupe d'objets construits. * +* Description : Charge le support d'une conservation d'objets en place. * +* * +* Retour : Gestionnaire de conservations construit ou None si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_object_storage_load(PyObject *self, PyObject *args) +{ + PyObject *result; /* Emplacement à retourner */ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ + int ret; /* Bilan de lecture des args. */ + GObjectStorage *storage; /* Mécanismes natifs */ + +#define OBJECT_STORAGE_LOAD_METHOD PYTHON_METHOD_DEF \ +( \ + load, "pbuf, /", \ + METH_STATIC | METH_VARARGS, py_object_storage, \ + "Construct a new storage from a buffer.\n" \ + "\n" \ + "The *pbuf* has to be an instance of type" \ + " pychrysalide.common.PackedBuffer.\n" \ + "\n" \ + "The result is a new pychrysalide.analysis.storage.ObjectStorage" \ + " object on success, *None* otherwise." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); + if (!ret) return NULL; + + storage = g_object_storage_load(pbuf); + + if (storage == NULL) + { + result = Py_None; + Py_INCREF(result); + } + else + { + result = pygobject_new(G_OBJECT(storage)); + g_object_unref(G_OBJECT(storage)); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = classe représentant une mémorisation de types. * +* args = arguments fournis à l'appel. * +* * +* Description : Sauvegarde le support d'une conservation d'objets en place. * * * * Retour : Bilan de l'opération. * * * @@ -208,37 +263,32 @@ static int py_object_storage_init(PyObject *self, PyObject *args, PyObject *kwds * * ******************************************************************************/ -static PyObject *py_object_storage_add_backend(PyObject *self, PyObject *args) +static PyObject *py_object_storage_store(PyObject *self, PyObject *args) { - PyObject *result; /* Bilan à retourner */ - const char *name; /* Désignation de groupe */ - const char *filename; /* Nom de fichier à associer */ + PyObject *result; /* Emplacement à retourner */ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ bool status; /* Bilan de l'opération */ -#define OBJECT_STORAGE_ADD_BACKEND_METHOD PYTHON_METHOD_DEF \ -( \ - add_backend, "$self, name, /, filename", \ - METH_VARARGS, py_object_storage, \ - "Add storage support for a new kind of GLib objects.\n" \ - "\n" \ - "The *name* is a string label for the group of target objects" \ - " and the optional *filename* points to a file used to load" \ - " objects.\n" \ - "\n" \ - "The result is a boolean value indicating the status of" \ - " the operation: True for success, False for failure." \ +#define OBJECT_STORAGE_STORE_METHOD PYTHON_METHOD_DEF \ +( \ + store, "$self, pbuf, /", \ + METH_VARARGS, py_object_storage, \ + "Save a storage into a buffer.\n" \ + "\n" \ + "The *pbuf* has to be an instance of type" \ + " pychrysalide.common.PackedBuffer.\n" \ + "\n" \ + "The result is *True* on success, *False* otherwise." \ ) - filename = NULL; - - ret = PyArg_ParseTuple(args, "s|s", &name, &filename); + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); if (!ret) return NULL; storage = G_OBJECT_STORAGE(pygobject_get(self)); - status = g_object_storage_add_backend(storage, name, filename); + status = g_object_storage_store(storage, pbuf); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -321,7 +371,7 @@ static PyObject *py_object_storage_unpack_object(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ const char *name; /* Désignation de groupe */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ GSerializableObject *object; /* Objet reconstruit ou NULL */ @@ -435,7 +485,7 @@ static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args) PyObject *result; /* Emplacement à retourner */ const char *name; /* Désignation de groupe */ GSerializableObject *object; /* Objet à traiter */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ GObjectStorage *storage; /* Mécanismes natifs */ bool status; /* Bilan de l'opération */ @@ -488,7 +538,8 @@ static PyObject *py_object_storage_pack_object(PyObject *self, PyObject *args) PyTypeObject *get_python_object_storage_type(void) { static PyMethodDef py_object_storage_methods[] = { - OBJECT_STORAGE_ADD_BACKEND_METHOD, + OBJECT_STORAGE_LOAD_METHOD, + OBJECT_STORAGE_STORE_METHOD, OBJECT_STORAGE_LOAD_OBJECT_METHOD, OBJECT_STORAGE_UNPACK_OBJECT_METHOD, OBJECT_STORAGE_STORE_OBJECT_METHOD, @@ -550,7 +601,7 @@ bool ensure_python_object_storage_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_STORAGE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_OBJECT_STORAGE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/storage/tpmem.c b/plugins/pychrysalide/analysis/storage/tpmem.c index 2cf659f..ae07008 100644 --- a/plugins/pychrysalide/analysis/storage/tpmem.c +++ b/plugins/pychrysalide/analysis/storage/tpmem.c @@ -52,8 +52,8 @@ static int py_type_memory_init(PyObject *, PyObject *, PyObject *); /* -------------------------- TAMPON POUR CODE DESASSEMBLE -------------------------- */ -/* Apprend tous les types mémorisés dans un flux. */ -static PyObject *py_type_memory_read_types(PyObject *, PyObject *); +/* Apprend tous les types mémorisés dans un tampon. */ +static PyObject *py_type_memory_load_types(PyObject *, PyObject *); /* Crée une nouvelle instance d'objet à partir de son type. */ static PyObject *py_type_memory_create_object(PyObject *, PyObject *); @@ -61,8 +61,8 @@ static PyObject *py_type_memory_create_object(PyObject *, PyObject *); /* Sauvegarde le type d'un objet instancié. */ static PyObject *py_type_memory_store_object_gtype(PyObject *, PyObject *); -/* Enregistre tous les types mémorisés dans un flux. */ -static PyObject *py_type_memory_write_types(PyObject *, PyObject *); +/* Enregistre tous les types mémorisés dans un tampon. */ +static PyObject *py_type_memory_store_types(PyObject *, PyObject *); @@ -108,7 +108,7 @@ static PyObject *py_type_memory_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -178,7 +178,7 @@ static int py_type_memory_init(PyObject *self, PyObject *args, PyObject *kwds) * Paramètres : self = classe représentant une mémorisation de types. * * args = arguments fournis à l'appel. * * * -* Description : Apprend tous les types mémorisés dans un flux. * +* Description : Apprend tous les types mémorisés dans un tampon. * * * * Retour : Bilan de l'opération. * * * @@ -186,36 +186,36 @@ static int py_type_memory_init(PyObject *self, PyObject *args, PyObject *kwds) * * ******************************************************************************/ -static PyObject *py_type_memory_read_types(PyObject *self, PyObject *args) +static PyObject *py_type_memory_load_types(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ - int fd; /* Flux ouvert en lecture */ + packed_buffer_t *pbuf; /* Tampon à consulter */ int ret; /* Bilan de lecture des args. */ GTypeMemory *tpmem; /* Mémorisation native */ bool status; /* Bilan de l'opération */ -#define TYPE_MEMORY_READ_TYPES_METHOD PYTHON_METHOD_DEF \ +#define TYPE_MEMORY_LOAD_TYPES_METHOD PYTHON_METHOD_DEF \ ( \ - read_types, "$self, fd", \ + load_types, "$self, pbuf", \ METH_VARARGS, py_type_memory, \ - "Read types from a stream.\n" \ + "Read types from a buffer.\n" \ "\n" \ "This operation is usually handled internally by the" \ " Chrysalide's core.\n" \ "\n" \ - "The *fd* parameter is an integer representing a valid" \ - " identifier for a file descriptor opened for reading." \ + "The *pbuf* parameter is a pychrysalide.common.PackedBuffer"\ + " instance providing buffered data to read." \ "\n" \ "The result is a boolean value indicating the status of" \ " the operation: True for success, False for failure." \ ) - ret = PyArg_ParseTuple(args, "i", &fd); + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); if (!ret) return NULL; tpmem = G_TYPE_MEMORY(pygobject_get(self)); - status = g_type_memory_read_types(tpmem, fd); + status = g_type_memory_load_types(tpmem, pbuf); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -241,7 +241,7 @@ static PyObject *py_type_memory_read_types(PyObject *self, PyObject *args) static PyObject *py_type_memory_create_object(PyObject *self, PyObject *args) { PyObject *result; /* Instance à retourner */ - packed_buffer *pbuf; /* Tampon à consulter */ + packed_buffer_t *pbuf; /* Tampon à consulter */ int ret; /* Bilan de lecture des args. */ GTypeMemory *tpmem; /* Mémorisation native */ GObject *obj; /* Instance retournée */ @@ -290,7 +290,7 @@ static PyObject *py_type_memory_store_object_gtype(PyObject *self, PyObject *arg { PyObject *result; /* Bilan à retourner */ GObject *obj; /* Instance à traiter */ - packed_buffer *pbuf; /* Tampon à consulter */ + packed_buffer_t *pbuf; /* Tampon à consulter */ int ret; /* Bilan de lecture des args. */ GTypeMemory *tpmem; /* Mémorisation native */ bool status; /* Bilan de l'opération */ @@ -330,7 +330,7 @@ static PyObject *py_type_memory_store_object_gtype(PyObject *self, PyObject *arg * Paramètres : self = classe représentant une mémorisation de types. * * args = arguments fournis à l'appel. * * * -* Description : Enregistre tous les types mémorisés dans un flux. * +* Description : Enregistre tous les types mémorisés dans un tampon. * * * * Retour : Bilan de l'opération. * * * @@ -338,36 +338,36 @@ static PyObject *py_type_memory_store_object_gtype(PyObject *self, PyObject *arg * * ******************************************************************************/ -static PyObject *py_type_memory_write_types(PyObject *self, PyObject *args) +static PyObject *py_type_memory_store_types(PyObject *self, PyObject *args) { PyObject *result; /* Bilan à retourner */ - int fd; /* Flux ouvert en lecture */ + packed_buffer_t *pbuf; /* Tampon à consulter */ int ret; /* Bilan de lecture des args. */ GTypeMemory *tpmem; /* Mémorisation native */ bool status; /* Bilan de l'opération */ -#define TYPE_MEMORY_WRITE_TYPES_METHOD PYTHON_METHOD_DEF \ +#define TYPE_MEMORY_STORE_TYPES_METHOD PYTHON_METHOD_DEF \ ( \ - write_types, "$self, fd", \ + store_types, "$self, pbuf", \ METH_VARARGS, py_type_memory, \ - "Write types into a stream.\n" \ + "Write types into a buffer.\n" \ "\n" \ "This operation is usually handled internally by the" \ " Chrysalide's core.\n" \ "\n" \ - "The *fd* parameter is an integer representing a valid" \ - " identifier for a file descriptor opened for writing." \ + "The *pbuf* parameter is a pychrysalide.common.PackedBuffer"\ + " instance providing buffered data to read." \ "\n" \ "The result is a boolean value indicating the status of" \ " the operation: True for success, False for failure." \ ) - ret = PyArg_ParseTuple(args, "i", &fd); + ret = PyArg_ParseTuple(args, "O&", convert_to_packed_buffer, &pbuf); if (!ret) return NULL; tpmem = G_TYPE_MEMORY(pygobject_get(self)); - status = g_type_memory_write_types(tpmem, fd); + status = g_type_memory_store_types(tpmem, pbuf); result = status ? Py_True : Py_False; Py_INCREF(result); @@ -392,10 +392,10 @@ static PyObject *py_type_memory_write_types(PyObject *self, PyObject *args) PyTypeObject *get_python_type_memory_type(void) { static PyMethodDef py_type_memory_methods[] = { - TYPE_MEMORY_READ_TYPES_METHOD, + TYPE_MEMORY_LOAD_TYPES_METHOD, TYPE_MEMORY_CREATE_OBJECT_METHOD, TYPE_MEMORY_STORE_OBJECT_GTYPE_METHOD, - TYPE_MEMORY_WRITE_TYPES_METHOD, + TYPE_MEMORY_STORE_TYPES_METHOD, { NULL } }; @@ -453,7 +453,7 @@ bool ensure_python_type_memory_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_TYPE_MEMORY, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_TYPE_MEMORY, type)) return false; } diff --git a/plugins/pychrysalide/analysis/type.c b/plugins/pychrysalide/analysis/type.c index 86a0ffb..ea8affd 100644 --- a/plugins/pychrysalide/analysis/type.c +++ b/plugins/pychrysalide/analysis/type.c @@ -158,7 +158,7 @@ static PyObject *py_data_type_new(PyTypeObject *type, PyObject *args, PyObject * if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -220,6 +220,7 @@ static void py_data_type_init_gclass(GDataTypeClass *class, gpointer unused) static guint py_data_type_hash_wrapper(const GDataType *type) { guint result; /* Empreinte à renvoyer */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -234,6 +235,8 @@ static guint py_data_type_hash_wrapper(const GDataType *type) result = 0; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_hash")) @@ -252,6 +255,8 @@ static guint py_data_type_hash_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -272,6 +277,7 @@ static guint py_data_type_hash_wrapper(const GDataType *type) static GDataType *py_data_type_dup_wrapper(const GDataType *type) { GDataType *result; /* Copie à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -287,6 +293,8 @@ static GDataType *py_data_type_dup_wrapper(const GDataType *type) result = NULL; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_dup")) @@ -308,6 +316,8 @@ static GDataType *py_data_type_dup_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -329,6 +339,7 @@ static GDataType *py_data_type_dup_wrapper(const GDataType *type) static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) { char *result; /* Etiquette à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *arg; /* Version Python de l'argument*/ PyObject *args; /* Arguments pour l'appel */ @@ -349,6 +360,8 @@ static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) result = NULL; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_to_string")) @@ -375,6 +388,8 @@ static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -395,6 +410,7 @@ static char *py_data_type_to_string_wrapper(const GDataType *type, bool include) static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -411,6 +427,8 @@ static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) result = true; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_handle_namespaces")) @@ -425,6 +443,8 @@ static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -445,6 +465,7 @@ static bool py_data_type_handle_namespaces_wrapper(const GDataType *type) static bool py_data_type_is_pointer_wrapper(const GDataType *type) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -461,6 +482,8 @@ static bool py_data_type_is_pointer_wrapper(const GDataType *type) result = false; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_is_pointer")) @@ -475,6 +498,8 @@ static bool py_data_type_is_pointer_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -495,6 +520,7 @@ static bool py_data_type_is_pointer_wrapper(const GDataType *type) static bool py_data_type_is_reference_wrapper(const GDataType *type) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -511,6 +537,8 @@ static bool py_data_type_is_reference_wrapper(const GDataType *type) result = false; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(type)); if (has_python_method(pyobj, "_is_reference")) @@ -525,6 +553,8 @@ static bool py_data_type_is_reference_wrapper(const GDataType *type) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -1095,7 +1125,7 @@ bool ensure_python_data_type_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_DATA_TYPE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_DATA_TYPE, type)) return false; if (!define_analysis_data_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/Makefile.am b/plugins/pychrysalide/analysis/types/Makefile.am index 8f1799f..697c998 100644 --- a/plugins/pychrysalide/analysis/types/Makefile.am +++ b/plugins/pychrysalide/analysis/types/Makefile.am @@ -1,30 +1,23 @@ noinst_LTLIBRARIES = libpychrysaanalysistypes.la -libpychrysaanalysistypes_la_SOURCES = \ - array.h array.c \ - basic.h basic.c \ - constants.h constants.c \ - cse.h cse.c \ - encaps.h encaps.c \ - expr.h expr.c \ - literal.h literal.c \ - module.h module.c \ - override.h override.c \ - proto.h proto.c \ +libpychrysaanalysistypes_la_SOURCES = \ + array.h array.c \ + basic.h basic.c \ + constants.h constants.c \ + cse.h cse.c \ + encaps.h encaps.c \ + expr.h expr.c \ + literal.h literal.c \ + module.h module.c \ + override.h override.c \ + proto.h proto.c \ template.h template.c -libpychrysaanalysistypes_la_LDFLAGS = +libpychrysaanalysistypes_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaanalysistypes_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/analysis/types/array.c b/plugins/pychrysalide/analysis/types/array.c index 8055316..88b773e 100644 --- a/plugins/pychrysalide/analysis/types/array.c +++ b/plugins/pychrysalide/analysis/types/array.c @@ -423,7 +423,7 @@ bool ensure_python_array_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_ARRAY_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_ARRAY_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/basic.c b/plugins/pychrysalide/analysis/types/basic.c index 9ae4f8f..19fb9d1 100644 --- a/plugins/pychrysalide/analysis/types/basic.c +++ b/plugins/pychrysalide/analysis/types/basic.c @@ -210,7 +210,7 @@ bool ensure_python_basic_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BASIC_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BASIC_TYPE, type)) return false; if (!define_basic_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/cse.c b/plugins/pychrysalide/analysis/types/cse.c index 7701d48..0aab4d9 100644 --- a/plugins/pychrysalide/analysis/types/cse.c +++ b/plugins/pychrysalide/analysis/types/cse.c @@ -262,7 +262,7 @@ bool ensure_python_class_enum_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_CLASS_ENUM_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_CLASS_ENUM_TYPE, type)) return false; if (!define_class_enum_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/encaps.c b/plugins/pychrysalide/analysis/types/encaps.c index 3a5acb5..bc9f4db 100644 --- a/plugins/pychrysalide/analysis/types/encaps.c +++ b/plugins/pychrysalide/analysis/types/encaps.c @@ -223,7 +223,7 @@ bool ensure_python_encapsulated_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_ENCAPSULATED_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_ENCAPSULATED_TYPE, type)) return false; if (!define_encapsulated_type_constants(type)) diff --git a/plugins/pychrysalide/analysis/types/expr.c b/plugins/pychrysalide/analysis/types/expr.c index 02cb02f..e3b2b0a 100644 --- a/plugins/pychrysalide/analysis/types/expr.c +++ b/plugins/pychrysalide/analysis/types/expr.c @@ -201,7 +201,7 @@ bool ensure_python_expr_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_EXPR_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_EXPR_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/literal.c b/plugins/pychrysalide/analysis/types/literal.c index e00104f..3d9d5e3 100644 --- a/plugins/pychrysalide/analysis/types/literal.c +++ b/plugins/pychrysalide/analysis/types/literal.c @@ -136,7 +136,7 @@ bool ensure_python_literal_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_LITERAL_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_LITERAL_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/override.c b/plugins/pychrysalide/analysis/types/override.c index 896163f..236a34c 100644 --- a/plugins/pychrysalide/analysis/types/override.c +++ b/plugins/pychrysalide/analysis/types/override.c @@ -247,7 +247,7 @@ bool ensure_python_override_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_OVERRIDE_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_OVERRIDE_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/proto.c b/plugins/pychrysalide/analysis/types/proto.c index 7c3ebed..1da3119 100644 --- a/plugins/pychrysalide/analysis/types/proto.c +++ b/plugins/pychrysalide/analysis/types/proto.c @@ -349,7 +349,7 @@ bool ensure_python_proto_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_PROTO_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_PROTO_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/types/template.c b/plugins/pychrysalide/analysis/types/template.c index 6fc50e4..68f390a 100644 --- a/plugins/pychrysalide/analysis/types/template.c +++ b/plugins/pychrysalide/analysis/types/template.c @@ -345,7 +345,7 @@ bool ensure_python_template_type_is_registered(void) if (!ensure_python_data_type_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_TEMPLATE_TYPE, type, get_python_data_type_type())) + if (!register_class_for_pygobject(dict, G_TYPE_TEMPLATE_TYPE, type)) return false; } diff --git a/plugins/pychrysalide/analysis/variable.c b/plugins/pychrysalide/analysis/variable.c index 3aeddf4..5f8d490 100644 --- a/plugins/pychrysalide/analysis/variable.c +++ b/plugins/pychrysalide/analysis/variable.c @@ -266,7 +266,7 @@ bool ensure_python_binary_variable_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BIN_VARIABLE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_VARIABLE, type)) return false; } diff --git a/plugins/pychrysalide/arch/Makefile.am b/plugins/pychrysalide/arch/Makefile.am index ab4ca23..c113f6e 100644 --- a/plugins/pychrysalide/arch/Makefile.am +++ b/plugins/pychrysalide/arch/Makefile.am @@ -1,22 +1,23 @@ noinst_LTLIBRARIES = libpychrysaarch.la -libpychrysaarch_la_SOURCES = \ - constants.h constants.c \ - context.h context.c \ - instriter.h instriter.c \ - instruction.h instruction.c \ - module.h module.c \ - operand.h operand.c \ - processor.h processor.c \ - register.h register.c \ +libpychrysaarch_la_SOURCES = \ + constants.h constants.c \ + context.h context.c \ + instriter.h instriter.c \ + instruction.h instruction.c \ + module.h module.c \ + operand.h operand.c \ + processor.h processor.c \ + register.h register.c \ vmpa.h vmpa.c -libpychrysaarch_la_LIBADD = \ +libpychrysaarch_la_LIBADD = \ instructions/libpychrysaarchinstructions.la \ operands/libpychrysaarchoperands.la -libpychrysaarch_la_LDFLAGS = +libpychrysaarch_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -24,9 +25,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarch_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = instructions operands diff --git a/plugins/pychrysalide/arch/context.c b/plugins/pychrysalide/arch/context.c index ce1ef01..79c782f 100644 --- a/plugins/pychrysalide/arch/context.c +++ b/plugins/pychrysalide/arch/context.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * context.c - équivalent Python du fichier "arch/context.h" + * context.c - équivalent Python du fichier "arch/context.c" * * Copyright (C) 2018 Cyrille Bagard * @@ -39,6 +39,7 @@ #include "../helpers.h" #include "../analysis/db/item.h" #include "../arch/vmpa.h" +#include "../format/preload.h" @@ -120,7 +121,7 @@ static PyObject *py_proc_context_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -518,7 +519,10 @@ bool ensure_python_proc_context_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PROC_CONTEXT, type, &PyGObject_Type)) + if (!ensure_python_preload_info_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_PROC_CONTEXT, type)) return false; if (!define_proc_context_constants(type)) diff --git a/plugins/pychrysalide/arch/instruction.c b/plugins/pychrysalide/arch/instruction.c index 3606cfe..0a9ba16 100644 --- a/plugins/pychrysalide/arch/instruction.c +++ b/plugins/pychrysalide/arch/instruction.c @@ -45,52 +45,7 @@ -/* -------------------- INTERFACE INTERNE POUR EXTENSIONS PYTHON -------------------- */ - - -/* Définition générique d'une instruction d'architecture (instance) */ -typedef struct _GPyArchInstruction -{ - GArchInstruction parent; /* A laisser en premier */ - - char *cached_keyword; /* Conservation de constante */ - -} GPyArchInstruction; - - -/* Définition générique d'une instruction d'architecture (classe) */ -typedef struct _GPyArchInstructionClass -{ - GArchInstructionClass parent; /* A laisser en premier */ - -} GPyArchInstructionClass; - - -#define G_TYPE_PYARCH_INSTRUCTION g_pyarch_instruction_get_type() -#define G_PYARCH_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstruction)) -#define G_IS_PYTHON_INSTRUCTION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYARCH_INSTRUCTION)) -#define G_PYARCH_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass)) -#define G_IS_PYTHON_INSTRUCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYARCH_INSTRUCTION)) -#define G_PYARCH_INSTRUCTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYARCH_INSTRUCTION, GPyArchInstructionClass)) - - -/* Indique le type défini pour une instruction d'architecture en Python. */ -GType g_pyarch_instruction_get_type(void); - -/* Initialise la classe générique des instructions en Python. */ -static void g_pyarch_instruction_class_init(GPyArchInstructionClass *); - -/* Initialise une instance d'opérande d'architecture. */ -static void g_pyarch_instruction_init(GPyArchInstruction *); - -/* Supprime toutes les références externes. */ -static void g_pyarch_instruction_dispose(GPyArchInstruction *); - -/* Procède à la libération totale de la mémoire. */ -static void g_pyarch_instruction_finalize(GPyArchInstruction *); - -/* Fournit le nom humain de l'instruction manipulée. */ -static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *); +static G_DEFINE_QUARK(cached_keyword, get_cached_keyword); @@ -101,11 +56,16 @@ static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *); static PyObject *py_arch_instruction_new(PyTypeObject *, PyObject *, PyObject *); /* Initialise la classe générique des instructions. */ -static void py_arch_instruction_init_gclass(GPyArchInstructionClass *, gpointer); +static void py_arch_instruction_init_gclass(GArchInstructionClass *, gpointer); + +CREATE_DYN_ABSTRACT_CONSTRUCTOR(arch_instruction, G_TYPE_ARCH_INSTRUCTION, py_arch_instruction_init_gclass); /* Initialise une instance sur la base du dérivé de GObject. */ static int py_arch_instruction_init(PyObject *, PyObject *, PyObject *); +/* Fournit le nom humain de l'instruction manipulée. */ +static const char *py_arch_instruction_get_class_keyword(GArchInstruction *); + /* --------------------------- MANIPULATION DES OPERANDES --------------------------- */ @@ -160,19 +120,16 @@ static PyObject *py_arch_instruction_get_keyword(PyObject *, void *); /* ---------------------------------------------------------------------------------- */ -/* INTERFACE INTERNE POUR EXTENSIONS PYTHON */ +/* GLUE POUR CREATION DEPUIS PYTHON */ /* ---------------------------------------------------------------------------------- */ -/* Indique le type défini pour une instruction d'architecture en Python. */ -G_DEFINE_TYPE(GPyArchInstruction, g_pyarch_instruction, G_TYPE_ARCH_INSTRUCTION); - - /****************************************************************************** * * -* Paramètres : klass = classe à initialiser. * +* Paramètres : class = classe à initialiser. * +* unused = données non utilisées ici. * * * -* Description : Initialise la classe générique des instructions en Python. * +* Description : Initialise la classe générique des instructions. * * * * Retour : - * * * @@ -180,78 +137,62 @@ G_DEFINE_TYPE(GPyArchInstruction, g_pyarch_instruction, G_TYPE_ARCH_INSTRUCTION) * * ******************************************************************************/ -static void g_pyarch_instruction_class_init(GPyArchInstructionClass *klass) +static void py_arch_instruction_init_gclass(GArchInstructionClass *class, gpointer unused) { - GObjectClass *object; /* Autre version de la classe */ GArchInstructionClass *instr; /* Encore une autre vision... */ - object = G_OBJECT_CLASS(klass); + instr = G_ARCH_INSTRUCTION_CLASS(class); - object->dispose = (GObjectFinalizeFunc/* ! */)g_pyarch_instruction_dispose; - object->finalize = (GObjectFinalizeFunc)g_pyarch_instruction_finalize; - - instr = G_ARCH_INSTRUCTION_CLASS(klass); - - instr->get_keyword = (get_instruction_keyword_fc)g_pyarch_instruction_get_keyword; + instr->get_keyword = (get_instruction_keyword_fc)py_arch_instruction_get_class_keyword; } /****************************************************************************** * * -* Paramètres : instr = instance à initialiser. * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Initialise une instance d'instruction d'architecture. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : - * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static void g_pyarch_instruction_init(GPyArchInstruction *instr) +static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kwds) { + unsigned short int uid; /* Indentifiant unique de type */ + const char *keyword; /* Désignation d'instruction */ + int ret; /* Bilan de lecture des args. */ + GArchInstruction *instr; /* Instruction à manipuler */ + GQuark cache_key; /* Emplacement local */ -} + static char *kwlist[] = { "uid", "keyword", NULL }; + /* Récupération des paramètres */ -/****************************************************************************** -* * -* Paramètres : instr = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword); + if (!ret) return -1; -static void g_pyarch_instruction_dispose(GPyArchInstruction *instr) -{ - G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->dispose(G_OBJECT(instr)); + /* Initialisation d'un objet GLib */ -} + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + /* Eléments de base */ -/****************************************************************************** -* * -* Paramètres : instr = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ + instr = G_ARCH_INSTRUCTION(pygobject_get(self)); -static void g_pyarch_instruction_finalize(GPyArchInstruction *instr) -{ - if (instr->cached_keyword) - free(instr->cached_keyword); + cache_key = get_cached_keyword_quark(); - G_OBJECT_CLASS(g_pyarch_instruction_parent_class)->finalize(G_OBJECT(instr)); + g_object_set_qdata_full(G_OBJECT(instr), cache_key, strdup(keyword), g_free); + + g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(instr), uid); + + return 0; } @@ -268,151 +209,21 @@ static void g_pyarch_instruction_finalize(GPyArchInstruction *instr) * * ******************************************************************************/ -static const char *g_pyarch_instruction_get_keyword(GPyArchInstruction *instr) +static const char *py_arch_instruction_get_class_keyword(GArchInstruction *instr) { const char *result; /* Désignation à retourner */ + GQuark cache_key; /* Emplacement local */ - result = instr->cached_keyword; + cache_key = get_cached_keyword_quark(); - return result; - -} - - -/* ---------------------------------------------------------------------------------- */ -/* GLUE POUR CREATION DEPUIS PYTHON */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * -* * -* Description : Accompagne la création d'une instance dérivée en Python. * -* * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_arch_instruction_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Objet à retourner */ - PyTypeObject *base; /* Type de base à dériver */ - bool first_time; /* Evite les multiples passages*/ - GType gtype; /* Nouveau type de processeur */ - bool status; /* Bilan d'un enregistrement */ - - /* Validations diverses */ - - base = get_python_arch_instruction_type(); - - if (type == base) - { - result = NULL; - PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); - goto exit; - } - - /* Mise en place d'un type dédié */ - - first_time = (g_type_from_name(type->tp_name) == 0); - - gtype = build_dynamic_type(G_TYPE_PYARCH_INSTRUCTION, type->tp_name, - (GClassInitFunc)py_arch_instruction_init_gclass, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type, base); - - if (!status) - { - result = NULL; - goto exit; - } - - } - - /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ - - result = PyType_GenericNew(type, args, kwds); - - exit: + result = g_object_get_qdata(G_OBJECT(instr), cache_key); + assert(result != NULL); return result; } -/****************************************************************************** -* * -* Paramètres : class = classe à initialiser. * -* unused = données non utilisées ici. * -* * -* Description : Initialise la classe générique des instructions. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void py_arch_instruction_init_gclass(GPyArchInstructionClass *class, gpointer unused) -{ - /// .... - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet à initialiser (théoriquement). * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Initialise une instance sur la base du dérivé de GObject. * -* * -* Retour : 0. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_arch_instruction_init(PyObject *self, PyObject *args, PyObject *kwds) -{ - unsigned short int uid; /* Indentifiant unique de type */ - const char *keyword; /* Désignation d'instruction */ - int ret; /* Bilan de lecture des args. */ - GPyArchInstruction *instr; /* Instruction à manipuler */ - - static char *kwlist[] = { "uid", "keyword", NULL }; - - /* Récupération des paramètres */ - - ret = PyArg_ParseTupleAndKeywords(args, kwds, "Hs", kwlist, &uid, &keyword); - if (!ret) return -1; - - /* Initialisation d'un objet GLib */ - - ret = forward_pygobjet_init(self); - if (ret == -1) return -1; - - /* Eléments de base */ - - instr = G_PYARCH_INSTRUCTION(pygobject_get(self)); - - instr->cached_keyword = strdup(keyword); - - g_arch_instruction_set_unique_id(G_ARCH_INSTRUCTION(instr), uid); - - return 0; - -} - - /* ---------------------------------------------------------------------------------- */ /* MANIPULATION DES OPERANDES */ @@ -1085,8 +896,7 @@ bool ensure_python_arch_instruction_is_registered(void) if (!ensure_python_line_generator_is_registered()) return false; - if (!_register_class_for_pygobject(dict, G_TYPE_PYARCH_INSTRUCTION, type, - &PyGObject_Type, get_python_line_generator_type(), NULL)) + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_INSTRUCTION, type)) return false; if (!define_arch_instruction_constants(type)) diff --git a/plugins/pychrysalide/arch/instructions/Makefile.am b/plugins/pychrysalide/arch/instructions/Makefile.am index 4c36acf..65efe42 100644 --- a/plugins/pychrysalide/arch/instructions/Makefile.am +++ b/plugins/pychrysalide/arch/instructions/Makefile.am @@ -2,24 +2,15 @@ noinst_LTLIBRARIES = libpychrysaarchinstructions.la libpychrysaarchinstructions_la_SOURCES = \ - constants.h constants.c \ - module.h module.c \ - raw.h raw.c \ + constants.h constants.c \ + module.h module.c \ + raw.h raw.c \ undefined.h undefined.c -libpychrysaarchinstructions_la_LIBADD = - -libpychrysaarchinstructions_la_LDFLAGS = +libpychrysaarchinstructions_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarchinstructions_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/arch/instructions/raw.c b/plugins/pychrysalide/arch/instructions/raw.c index c1366c6..7e58b96 100644 --- a/plugins/pychrysalide/arch/instructions/raw.c +++ b/plugins/pychrysalide/arch/instructions/raw.c @@ -99,7 +99,7 @@ static PyObject *py_raw_instruction_new(PyTypeObject *type, PyObject *args, PyOb if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -458,7 +458,7 @@ bool ensure_python_raw_instruction_is_registered(void) if (!ensure_python_arch_instruction_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, type, get_python_arch_instruction_type())) + if (!register_class_for_pygobject(dict, G_TYPE_RAW_INSTRUCTION, type)) return false; if (!define_raw_instruction_constants(type)) diff --git a/plugins/pychrysalide/arch/instructions/undefined.c b/plugins/pychrysalide/arch/instructions/undefined.c index 5741609..1246daa 100644 --- a/plugins/pychrysalide/arch/instructions/undefined.c +++ b/plugins/pychrysalide/arch/instructions/undefined.c @@ -88,7 +88,7 @@ static PyObject *py_undef_instruction_new(PyTypeObject *type, PyObject *args, Py if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -130,7 +130,7 @@ static int py_undef_instruction_init(PyObject *self, PyObject *args, PyObject *k unsigned long behavior; /* Conséquence pour l'instruct°*/ int ret; /* Bilan de lecture des args. */ GUndefInstruction *instr; /* Instruction à manipuler */ - undef_obj_extra *extra; /* Données insérées à modifier */ + undef_extra_data_t *extra; /* Données insérées à modifier */ static char *kwlist[] = { "behavior", NULL }; @@ -285,7 +285,7 @@ bool ensure_python_undefined_instruction_is_registered(void) if (!ensure_python_arch_instruction_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_UNDEF_INSTRUCTION, type, get_python_arch_instruction_type())) + if (!register_class_for_pygobject(dict, G_TYPE_UNDEF_INSTRUCTION, type)) return false; if (!define_undefined_instruction_constants(type)) diff --git a/plugins/pychrysalide/arch/operand.c b/plugins/pychrysalide/arch/operand.c index 7fa5118..0aee4f7 100644 --- a/plugins/pychrysalide/arch/operand.c +++ b/plugins/pychrysalide/arch/operand.c @@ -35,6 +35,7 @@ #include "../access.h" #include "../helpers.h" +#include "../glibext/singleton.h" @@ -48,7 +49,7 @@ static PyObject *py_arch_operand_new(PyTypeObject *, PyObject *, PyObject *); static void py_arch_operand_init_gclass(GArchOperandClass *, gpointer); /* Compare un opérande avec un autre. */ -static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *); +static int py_arch_operand___cmp___wrapper(const GArchOperand *, const GArchOperand *, bool); /* Détermine le chemin conduisant à un opérande interne. */ static char *py_arch_operand_find_inner_operand_path_wrapper(const GArchOperand *, const GArchOperand *); @@ -59,9 +60,13 @@ static GArchOperand *py_arch_operand_get_inner_operand_from_path_wrapper(const G /* Traduit un opérande en version humainement lisible. */ static void py_arch_operand_print_wrapper(const GArchOperand *, GBufferLine *); +#ifdef INCLUDE_GTK_SUPPORT + /* Construit un petit résumé concis de l'opérande. */ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *, const GLoadedBinary *); +#endif + /* ------------------------ DEFINITION D'OPERANDE QUELCONQUE ------------------------ */ @@ -144,7 +149,7 @@ static PyObject *py_arch_operand_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -185,15 +190,18 @@ static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unuse class->get_inner = py_arch_operand_get_inner_operand_from_path_wrapper; class->print = py_arch_operand_print_wrapper; +#ifdef INCLUDE_GTK_SUPPORT class->build_tooltip = py_arch_operand_build_tooltip_wrapper; +#endif } /****************************************************************************** * * -* Paramètres : a = premier opérande à consulter. * -* b = second opérande à consulter. * +* Paramètres : a = premier opérande à consulter. * +* b = second opérande à consulter. * +* lock = précise le besoin en verrouillage. * * * * Description : Compare un opérande avec un autre. * * * @@ -203,7 +211,7 @@ static void py_arch_operand_init_gclass(GArchOperandClass *class, gpointer unuse * * ******************************************************************************/ -static int py_arch_operand___cmp___wrapper(const GArchOperand *a, const GArchOperand *b) +static int py_arch_operand___cmp___wrapper(const GArchOperand *a, const GArchOperand *b, bool lock) { int result; /* Empreinte à retourner */ PyGILState_STATE gstate; /* Sauvegarde d'environnement */ @@ -454,6 +462,9 @@ static void py_arch_operand_print_wrapper(const GArchOperand *operand, GBufferLi } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : operand = opérande à consulter. * @@ -520,6 +531,9 @@ static char *py_arch_operand_build_tooltip_wrapper(const GArchOperand *operand, } +#endif + + /* ---------------------------------------------------------------------------------- */ /* DEFINITION D'OPERANDE QUELCONQUE */ @@ -558,7 +572,7 @@ static PyObject *py_arch_operand_richcompare(PyObject *a, PyObject *b, int op) reg_a = G_ARCH_OPERAND(pygobject_get(a)); reg_b = G_ARCH_OPERAND(pygobject_get(b)); - status = py_arch_operand___cmp___wrapper(reg_a, reg_b); + status = py_arch_operand___cmp___wrapper(reg_a, reg_b, true); result = status_to_rich_cmp_state(status, op); @@ -707,7 +721,9 @@ PyTypeObject *get_python_arch_operand_type(void) ARCH_OPERAND_FIND_INNER_OPERAND_PATH_WRAPPER, ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_WRAPPER, ARCH_OPERAND_PRINT_WRAPPER, +#ifdef INCLUDE_GTK_SUPPORT ARCH_OPERAND_BUILD_TOOLTIP_WRAPPER, +#endif ARCH_OPERAND_FIND_INNER_OPERAND_PATH_METHOD, ARCH_OPERAND_GET_INNER_OPERAND_FROM_PATH_METHOD, { NULL } @@ -768,7 +784,10 @@ bool ensure_python_arch_operand_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type, &PyGObject_Type)) + if (!ensure_python_singleton_candidate_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/operands/Makefile.am b/plugins/pychrysalide/arch/operands/Makefile.am index 725096f..a41cbbb 100644 --- a/plugins/pychrysalide/arch/operands/Makefile.am +++ b/plugins/pychrysalide/arch/operands/Makefile.am @@ -1,30 +1,22 @@ noinst_LTLIBRARIES = libpychrysaarchoperands.la -libpychrysaarchoperands_la_SOURCES = \ - constants.h constants.c \ - feeder.h feeder.c \ - immediate.h immediate.c \ - module.h module.c \ - proxy.h proxy.c \ - register.h register.c \ - rename.h rename.c \ - target.h target.c \ +libpychrysaarchoperands_la_SOURCES = \ + constants.h constants.c \ + feeder.h feeder.c \ + immediate.h immediate.c \ + known.h known.c \ + module.h module.c \ + proxy.h proxy.c \ + register.h register.c \ + rename.h rename.c \ + target.h target.c \ targetable.h targetable.c -libpychrysaarchoperands_la_LIBADD = - -libpychrysaarchoperands_la_LDFLAGS = +libpychrysaarchoperands_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaarchoperands_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/arch/operands/immediate.c b/plugins/pychrysalide/arch/operands/immediate.c index 2634352..2239eb2 100644 --- a/plugins/pychrysalide/arch/operands/immediate.c +++ b/plugins/pychrysalide/arch/operands/immediate.c @@ -46,9 +46,6 @@ -/* ------------------------- OPERANDE POUR VALEUR IMMEDIATE ------------------------- */ - - /* Crée un nouvel objet Python de type 'ImmOperand'. */ static PyObject *py_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); @@ -64,18 +61,6 @@ static PyObject *py_imm_operand_get_size(PyObject *, void *); /* Fournit la valeur portée par une opérande numérique. */ static PyObject *py_imm_operand_get_value(PyObject *, void *); -/* Indique si l'affichage est complété avec des zéros. */ -static PyObject *py_imm_operand_get_default_padding(PyObject *self, void *); - -/* Précise si des zéro doivent compléter l'affichage ou non. */ -static int py_imm_operand_set_default_padding(PyObject *, PyObject *, void *); - -/* Indique si l'affichage est complété avec des zéros. */ -static PyObject *py_imm_operand_get_padding(PyObject *self, void *); - -/* Précise si des zéro doivent compléter l'affichage ou non. */ -static int py_imm_operand_set_padding(PyObject *, PyObject *, void *); - /* Indique le format textuel par défaut de la valeur. */ static PyObject *py_imm_operand_get_default_display(PyObject *, void *); @@ -90,19 +75,6 @@ static int py_imm_operand_set_display(PyObject *, PyObject *, void *); -/* ----------------------- REMPLACEMENT DE VALEURS IMMEDIATES ----------------------- */ - - -/* Crée un nouvel objet Python de type 'KnownImmOperand'. */ -static PyObject *py_known_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); - - - -/* ---------------------------------------------------------------------------------- */ -/* OPERANDE POUR VALEUR IMMEDIATE */ -/* ---------------------------------------------------------------------------------- */ - - /****************************************************************************** * * * Paramètres : type = type de l'objet à instancier. * @@ -391,158 +363,6 @@ static PyObject *py_imm_operand_get_value(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Indique si l'affichage est complété avec des zéros. * -* * -* Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_imm_operand_get_default_padding(PyObject *self, void *closure) -{ - PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ - bool padding; /* Bourrage en préfixe ? */ - -#define IMM_OPERAND_DEFAULT_PADDING_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - default_padding, py_imm_operand, \ - "Get or set the status of default padding with zeros in front of the" \ - " textual representation." \ - "\n" \ - "The status is a boolean value." \ -) - - operand = G_IMM_OPERAND(pygobject_get(self)); - - padding = g_imm_operand_get_default_padding(operand); - - result = padding ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* value = valeur fournie à intégrer ou prendre en compte. * -* closure = non utilisé ici. * -* * -* Description : Précise si des zéro doivent compléter l'affichage ou non. * -* * -* Retour : Bilan de l'opération pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_imm_operand_set_default_padding(PyObject *self, PyObject *value, void *closure) -{ - bool padding; /* Bourrage en préfixe ? */ - GImmOperand *operand; /* Version GLib de l'opérande */ - - if (!PyBool_Check(value)) - { - PyErr_SetString(PyExc_TypeError, _("Invalid padding state")); - return -1; - } - - padding = (value == Py_True); - - operand = G_IMM_OPERAND(pygobject_get(self)); - - g_imm_operand_set_default_padding(operand, padding); - - return 0; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Indique si l'affichage est complété avec des zéros. * -* * -* Retour : true si des zéro sont ajoutés à l'affichage, false sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_imm_operand_get_padding(PyObject *self, void *closure) -{ - PyObject *result; /* Instance Python à retourner */ - GImmOperand *operand; /* Version GLib de l'opérande */ - bool padding; /* Bourrage en préfixe ? */ - -#define IMM_OPERAND_PADDING_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - padding, py_imm_operand, \ - "Get or set the status of padding with zeros in front of the" \ - " textual representation." \ - "\n" \ - "The status is a boolean value." \ -) - - operand = G_IMM_OPERAND(pygobject_get(self)); - - padding = g_imm_operand_does_padding(operand); - - result = padding ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* value = valeur fournie à intégrer ou prendre en compte. * -* closure = non utilisé ici. * -* * -* Description : Précise si des zéro doivent compléter l'affichage ou non. * -* * -* Retour : Bilan de l'opération pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static int py_imm_operand_set_padding(PyObject *self, PyObject *value, void *closure) -{ - bool padding; /* Bourrage en préfixe ? */ - GImmOperand *operand; /* Version GLib de l'opérande */ - - if (!PyBool_Check(value)) - { - PyErr_SetString(PyExc_TypeError, _("Invalid padding state")); - return -1; - } - - padding = (value == Py_True); - - operand = G_IMM_OPERAND(pygobject_get(self)); - - g_imm_operand_pad(operand, padding); - - return 0; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * * Description : Indique le format textuel par défaut de la valeur. * * * * Retour : Format global d'un affichage de valeur. * @@ -721,8 +541,6 @@ PyTypeObject *get_python_imm_operand_type(void) static PyGetSetDef py_imm_operand_getseters[] = { IMM_OPERAND_SIZE_ATTRIB, IMM_OPERAND_VALUE_ATTRIB, - IMM_OPERAND_DEFAULT_PADDING_ATTRIB, - IMM_OPERAND_PADDING_ATTRIB, IMM_OPERAND_DEFAULT_DISPLAY_ATTRIB, IMM_OPERAND_DISPLAY_ATTRIB, { NULL } @@ -785,7 +603,7 @@ bool ensure_python_imm_operand_is_registered(void) if (!ensure_python_renameable_operand_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type, get_python_arch_operand_type())) + if (!register_class_for_pygobject(dict, G_TYPE_IMM_OPERAND, type)) return false; if (!define_imm_operand_constants(type)) @@ -841,189 +659,3 @@ int convert_to_imm_operand(PyObject *arg, void *dst) return result; } - - - -/* ---------------------------------------------------------------------------------- */ -/* REMPLACEMENT DE VALEURS IMMEDIATES */ -/* ---------------------------------------------------------------------------------- */ - - -/****************************************************************************** -* * -* Paramètres : type = type de l'objet à instancier. * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Crée un nouvel objet Python de type 'KnownImmOperand'. * -* * -* Retour : Instance Python mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Instance à retourner */ - GImmOperand *imm; /* Opérande à remplacer */ - const char *alt; /* Impression alternative */ - int ret; /* Bilan de lecture des args. */ - GArchOperand *operand; /* Création GLib à transmettre */ - -#define KNOWN_IMM_OPERAND_DOC \ - "The KnownImmOperand provides replacement of" \ - " pychrysalide.arch.operands.ImmOperand instances by an alternative" \ - " text.\n" \ - "\n" \ - "Instances can be created using the following constructor:\n" \ - "\n" \ - " KnownImmOperand(imm, alt)" \ - "\n" \ - "Where imm is an operand of type pychrysalide.arch.operands.ImmOperand" \ - " and alt is a string providing the text to be rendered at object" \ - " display." - - ret = PyArg_ParseTuple(args, "O&s", convert_to_imm_operand, &imm, &alt); - if (!ret) return NULL; - - operand = g_known_imm_operand_new(imm, alt); - - result = pygobject_new(G_OBJECT(operand)); - - g_object_unref(operand); - - return (PyObject *)result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Fournit un accès à une définition de type à diffuser. * -* * -* Retour : Définition d'objet pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PyTypeObject *get_python_known_imm_operand_type(void) -{ - static PyMethodDef py_known_imm_operand_methods[] = { - { NULL } - }; - - static PyGetSetDef py_known_imm_operand_getseters[] = { - { NULL } - }; - - static PyTypeObject py_known_imm_operand_type = { - - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "pychrysalide.arch.operands.KnownImmOperand", - .tp_basicsize = sizeof(PyGObject), - - .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, - - .tp_doc = KNOWN_IMM_OPERAND_DOC, - - .tp_methods = py_known_imm_operand_methods, - .tp_getset = py_known_imm_operand_getseters, - .tp_new = py_known_imm_operand_new - - }; - - return &py_known_imm_operand_type; - -} - - -/****************************************************************************** -* * -* Paramètres : module = module dont la définition est à compléter. * -* * -* Description : Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool ensure_python_known_imm_operand_is_registered(void) -{ - PyTypeObject *type; /* Type Python 'ImmOperand' */ - PyObject *module; /* Module à recompléter */ - PyObject *dict; /* Dictionnaire du module */ - - type = get_python_known_imm_operand_type(); - - if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) - { - module = get_access_to_python_module("pychrysalide.arch.operands"); - - dict = PyModule_GetDict(module); - - if (!ensure_python_imm_operand_is_registered()) - return false; - - if (!ensure_python_renamed_operand_is_registered()) - return false; - - if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type, get_python_imm_operand_type())) - return false; - - } - - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : arg = argument quelconque à tenter de convertir. * -* dst = destination des valeurs récupérées en cas de succès. * -* * -* Description : Tente de convertir en remplaçant d'opérande d'immédiat. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_known_imm_operand(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - - result = PyObject_IsInstance(arg, (PyObject *)get_python_known_imm_operand_type()); - - switch (result) - { - case -1: - /* L'exception est déjà fixée par Python */ - result = 0; - break; - - case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to known immediate operand"); - break; - - case 1: - *((GKnownImmOperand **)dst) = G_KNOWN_IMM_OPERAND(pygobject_get(arg)); - break; - - default: - assert(false); - break; - - } - - return result; - -} diff --git a/plugins/pychrysalide/arch/operands/immediate.h b/plugins/pychrysalide/arch/operands/immediate.h index 15d2c3e..4a1e6de 100644 --- a/plugins/pychrysalide/arch/operands/immediate.h +++ b/plugins/pychrysalide/arch/operands/immediate.h @@ -31,9 +31,6 @@ -/* ------------------------- OPERANDE POUR VALEUR IMMEDIATE ------------------------- */ - - /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_imm_operand_type(void); @@ -45,18 +42,4 @@ int convert_to_imm_operand(PyObject *, void *); -/* ----------------------- REMPLACEMENT DE VALEURS IMMEDIATES ----------------------- */ - - -/* Fournit un accès à une définition de type à diffuser. */ -PyTypeObject *get_python_known_imm_operand_type(void); - -/* Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. */ -bool ensure_python_known_imm_operand_is_registered(void); - -/* Tente de convertir en remplaçant d'opérande d'immédiat. */ -int convert_to_known_imm_operand(PyObject *, void *); - - - #endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_IMMEDIATE_H */ diff --git a/plugins/pychrysalide/arch/operands/known.c b/plugins/pychrysalide/arch/operands/known.c new file mode 100644 index 0000000..fab426e --- /dev/null +++ b/plugins/pychrysalide/arch/operands/known.c @@ -0,0 +1,224 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * known.c - équivalent Python du fichier "arch/operands/known.h" + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "known.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <arch/operands/known.h> + + +#include "immediate.h" +#include "rename.h" +#include "../../access.h" +#include "../../helpers.h" + + + +/* Crée un nouvel objet Python de type 'KnownImmOperand'. */ +static PyObject *py_known_imm_operand_new(PyTypeObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : type = type de l'objet à instancier. * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Crée un nouvel objet Python de type 'KnownImmOperand'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_known_imm_operand_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + GImmOperand *imm; /* Opérande à remplacer */ + const char *alt; /* Impression alternative */ + int ret; /* Bilan de lecture des args. */ + GArchOperand *operand; /* Création GLib à transmettre */ + +#define KNOWN_IMM_OPERAND_DOC \ + "The KnownImmOperand provides replacement of" \ + " pychrysalide.arch.operands.ImmOperand instances by an alternative" \ + " text.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " KnownImmOperand(imm, alt)" \ + "\n" \ + "Where imm is an operand of type pychrysalide.arch.operands.ImmOperand" \ + " and alt is a string providing the text to be rendered at object" \ + " display." + + ret = PyArg_ParseTuple(args, "O&s", convert_to_imm_operand, &imm, &alt); + if (!ret) return NULL; + + operand = g_known_imm_operand_new(imm, alt); + + result = pygobject_new(G_OBJECT(operand)); + + g_object_unref(operand); + + return (PyObject *)result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_known_imm_operand_type(void) +{ + static PyMethodDef py_known_imm_operand_methods[] = { + { NULL } + }; + + static PyGetSetDef py_known_imm_operand_getseters[] = { + { NULL } + }; + + static PyTypeObject py_known_imm_operand_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.arch.operands.KnownImmOperand", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = KNOWN_IMM_OPERAND_DOC, + + .tp_methods = py_known_imm_operand_methods, + .tp_getset = py_known_imm_operand_getseters, + .tp_new = py_known_imm_operand_new + + }; + + return &py_known_imm_operand_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_known_imm_operand_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ImmOperand' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_known_imm_operand_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.arch.operands"); + + dict = PyModule_GetDict(module); + + if (!ensure_python_imm_operand_is_registered()) + return false; + + if (!ensure_python_renamed_operand_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_IMM_OPERAND, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en remplaçant d'opérande d'immédiat. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_known_imm_operand(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_known_imm_operand_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to known immediate operand"); + break; + + case 1: + *((GKnownImmOperand **)dst) = G_KNOWN_IMM_OPERAND(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/arch/operands/known.h b/plugins/pychrysalide/arch/operands/known.h new file mode 100644 index 0000000..b5ced68 --- /dev/null +++ b/plugins/pychrysalide/arch/operands/known.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * known.h - prototypes pour l'équivalent Python du fichier "arch/operands/known.h" + * + * Copyright (C) 2020 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_KNOWN_H +#define _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_KNOWN_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_known_imm_operand_type(void); + +/* Prend en charge l'objet 'pychrysalide.arch.KnownImmOperand'. */ +bool ensure_python_known_imm_operand_is_registered(void); + +/* Tente de convertir en remplaçant d'opérande d'immédiat. */ +int convert_to_known_imm_operand(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_ARCH_OPERANDS_KNOWN_H */ diff --git a/plugins/pychrysalide/arch/operands/module.c b/plugins/pychrysalide/arch/operands/module.c index f1669fb..89adecc 100644 --- a/plugins/pychrysalide/arch/operands/module.c +++ b/plugins/pychrysalide/arch/operands/module.c @@ -30,6 +30,7 @@ #include "feeder.h" #include "immediate.h" +#include "known.h" #include "proxy.h" #include "register.h" #include "rename.h" diff --git a/plugins/pychrysalide/arch/operands/proxy.c b/plugins/pychrysalide/arch/operands/proxy.c index 1cfd4a4..5009d29 100644 --- a/plugins/pychrysalide/arch/operands/proxy.c +++ b/plugins/pychrysalide/arch/operands/proxy.c @@ -105,7 +105,7 @@ static PyObject *py_proxy_operand_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -319,7 +319,10 @@ bool ensure_python_proxy_operand_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PROXY_OPERAND, type, get_python_arch_operand_type())) + if (!ensure_python_arch_operand_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_PROXY_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/operands/register.c b/plugins/pychrysalide/arch/operands/register.c index fcf838c..2a48a0f 100644 --- a/plugins/pychrysalide/arch/operands/register.c +++ b/plugins/pychrysalide/arch/operands/register.c @@ -67,9 +67,6 @@ static PyObject *py_register_operand__print(PyObject *, PyObject *); /* Fournit le registre associé à l'opérande. */ static PyObject *py_register_operand_get_register(PyObject *, void *); -/* Indique le type d'accès réalisé sur l'opérande. */ -static PyObject *py_register_operand_is_written(PyObject *, void *); - /* ---------------------------------------------------------------------------------- */ @@ -115,7 +112,7 @@ static PyObject *py_register_operand_new(PyTypeObject *type, PyObject *args, PyO if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -357,43 +354,6 @@ static PyObject *py_register_operand_get_register(PyObject *self, void *closure) /****************************************************************************** * * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Indique le type d'accès réalisé sur l'opérande. * -* * -* Retour : Type d'accès : True en cas d'écriture, False sinon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_register_operand_is_written(PyObject *self, void *closure) -{ - PyObject *result; /* Résultat à retourner */ - GRegisterOperand *operand; /* Version GLib du type */ - bool status; /* Statut de la ligne */ - -#define REGISTER_OPERAND_IS_WRITTEN_ATTRIB PYTHON_IS_DEF_FULL \ -( \ - written, py_register_operand, \ - "Kind of access for the register when its instruction is executed." \ -) - - operand = G_REGISTER_OPERAND(pygobject_get(self)); - - status = g_register_operand_is_written(operand); - - result = status ? Py_True : Py_False; - Py_INCREF(result); - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : - * * * * Description : Fournit un accès à une définition de type à diffuser. * @@ -414,7 +374,6 @@ PyTypeObject *get_python_register_operand_type(void) static PyGetSetDef py_register_operand_getseters[] = { REGISTER_OPERAND_REGISTER_ATTRIB, - REGISTER_OPERAND_IS_WRITTEN_ATTRIB, { NULL } }; @@ -468,7 +427,10 @@ bool ensure_python_register_operand_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_REGISTER_OPERAND, type, get_python_arch_operand_type())) + if (!ensure_python_arch_operand_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_REGISTER_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/operands/target.c b/plugins/pychrysalide/arch/operands/target.c index 5cd9f59..b8cd536 100644 --- a/plugins/pychrysalide/arch/operands/target.c +++ b/plugins/pychrysalide/arch/operands/target.c @@ -115,7 +115,7 @@ static PyObject *py_target_operand_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -176,7 +176,8 @@ static int py_target_operand_init(PyObject *self, PyObject *args, PyObject *kwds MemoryDataSize size; /* Taille des adresses mémoire */ vmpa2t *addr; /* Emplacement de symbole */ int ret; /* Bilan de lecture des args. */ - GTargetOperand *operand; /* Opérande à manipuler */ + GTargetOperand *operand; /* Opérande à manipuler */ + tarop_extra_data_t *extra; /* Données insérées à modifier */ #define TARGET_OPERAND_DOC \ "The TargetOperand object translates immediate values as symbols.\n" \ @@ -203,7 +204,10 @@ static int py_target_operand_init(PyObject *self, PyObject *args, PyObject *kwds operand = G_TARGET_OPERAND(pygobject_get(self)); - operand->size = size; + extra = GET_TARGET_OP_EXTRA(operand); + + extra->size = size; + copy_vmpa(&operand->addr, addr); clean_vmpa_arg(addr); @@ -425,10 +429,13 @@ bool ensure_python_target_operand_is_registered(void) dict = PyModule_GetDict(module); + if (!ensure_python_arch_operand_is_registered()) + return false; + if (!ensure_python_targetable_operand_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_TARGET_OPERAND, type, get_python_arch_operand_type())) + if (!register_class_for_pygobject(dict, G_TYPE_TARGET_OPERAND, type)) return false; } diff --git a/plugins/pychrysalide/arch/processor.c b/plugins/pychrysalide/arch/processor.c index 80b55d3..00b472f 100644 --- a/plugins/pychrysalide/arch/processor.c +++ b/plugins/pychrysalide/arch/processor.c @@ -186,7 +186,7 @@ static PyObject *py_arch_processor_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1452,7 +1452,7 @@ bool ensure_python_arch_processor_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_PROCESSOR, type)) return false; if (!define_arch_processor_constants(type)) diff --git a/plugins/pychrysalide/arch/register.c b/plugins/pychrysalide/arch/register.c index 61da77f..615a5b7 100644 --- a/plugins/pychrysalide/arch/register.c +++ b/plugins/pychrysalide/arch/register.c @@ -36,6 +36,7 @@ #include "../access.h" #include "../helpers.h" +#include "../analysis/storage/serialize.h" @@ -143,7 +144,7 @@ static PyObject *py_arch_register_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -682,7 +683,10 @@ bool ensure_python_arch_register_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type, &PyGObject_Type)) + if (!ensure_python_serializable_object_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_ARCH_REGISTER, type)) return false; } diff --git a/plugins/pychrysalide/common/Makefile.am b/plugins/pychrysalide/common/Makefile.am index 1fb268d..b5249b9 100644 --- a/plugins/pychrysalide/common/Makefile.am +++ b/plugins/pychrysalide/common/Makefile.am @@ -1,25 +1,21 @@ noinst_LTLIBRARIES = libpychrysacommon.la -libpychrysacommon_la_SOURCES = \ - bits.h bits.c \ - fnv1a.h fnv1a.c \ - hex.h hex.c \ - leb128.h leb128.c \ - module.h module.c \ - packed.h packed.c \ - pathname.h pathname.c \ +libpychrysacommon_la_SOURCES = \ + bits.h bits.c \ + fnv1a.h fnv1a.c \ + hex.h hex.c \ + itoa.h itoa.c \ + leb128.h leb128.c \ + module.h module.c \ + packed.h packed.c \ + pathname.h pathname.c \ pearson.h pearson.c -libpychrysacommon_la_LDFLAGS = +libpychrysacommon_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysacommon_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/common/bits.c b/plugins/pychrysalide/common/bits.c index 73fd55b..a127251 100644 --- a/plugins/pychrysalide/common/bits.c +++ b/plugins/pychrysalide/common/bits.c @@ -65,6 +65,9 @@ static PyObject *py_bitfield_richcompare(PyObject *, PyObject *, int); /* Crée une copie d'un champ de bits classique. */ static PyObject *py_bitfield_dup(PyObject *, PyObject *); +/* Redimensionne un champ de bits. */ +static PyObject *py_bitfield_resize(PyObject *, PyObject *); + /* Bascule à 0 un champ de bits dans son intégralité. */ static PyObject *py_bitfield_reset_all(PyObject *, PyObject *); @@ -77,6 +80,9 @@ static PyObject *py_bitfield_reset(PyObject *, PyObject *); /* Bascule à 1 une partie d'un champ de bits. */ static PyObject *py_bitfield_set(PyObject *, PyObject *); +/* Réalise une opération OU logique entre deux champs de bits. */ +static PyObject *py_bitfield_or_at(PyObject *, PyObject *); + /* Détermine si un bit est à 1 dans un champ de bits. */ static PyObject *py_bitfield_test(PyObject *, PyObject *); @@ -86,6 +92,15 @@ static PyObject *py_bitfield_test_none(PyObject *, PyObject *); /* Détermine si un ensemble de bits est à 1 dans un champ. */ static PyObject *py_bitfield_test_all(PyObject *, PyObject *); +/* Teste l'état à 0 de bits selon un masque de bits. */ +static PyObject *py_bitfield_test_zeros_with(PyObject *, PyObject *); + +/* Teste l'état à 1 de bits selon un masque de bits. */ +static PyObject *py_bitfield_test_ones_with(PyObject *, PyObject *); + +/* Recherche un prochain bit défini dans un champ de bits. */ +static PyObject *py_bitfield_find_next_set(PyObject *, PyObject *); + /* Indique la taille d'un champ de bits donné. */ static PyObject *py_bitfield_get_size(PyObject *, void *); @@ -399,6 +414,47 @@ static PyObject *py_bitfield_dup(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = champ de bits à dupliquer. * +* args = non utilisé ici. * +* * +* Description : Redimensionne un champ de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_resize(PyObject *self, PyObject *args) +{ + unsigned long length; /* Nouvelle taille à respecter */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + +#define BITFIELD_RESIZE_METHOD PYTHON_METHOD_DEF \ +( \ + resize, "$self, length, /", \ + METH_VARARGS, py_bitfield, \ + "Resize a bitfield and fix its new size to *length*.\n" \ + "\n" \ + "The new bits get initialized to the same state used at the" \ + " bitfield creation." \ +) + + ret = PyArg_ParseTuple(args, "k", &length); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + resize_bit_field(&bf->native, length); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * * Paramètres : self = champ de bits à modifier. * * args = non utilisé ici. * * * @@ -552,6 +608,49 @@ static PyObject *py_bitfield_set(PyObject *self, PyObject *args) * Paramètres : self = champ de bits à consulter. * * args = arguments fournis pour la conduite de l'opération. * * * +* Description : Réalise une opération OU logique entre deux champs de bits. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_or_at(PyObject *self, PyObject *args) +{ + bitfield_t *src; /* Seconde champ de bits */ + unsigned long first; /* Indice du premier bit testé */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + +#define BITFIELD_OR_AT_METHOD PYTHON_METHOD_DEF \ +( \ + or_at, "$self, src, first, /", \ + METH_VARARGS, py_bitfield, \ + "Perform an OR operation with another bitfield.\n" \ + "\n" \ + "The *src* argument is expected to be another" \ + " pychrysalide.common.BitField instance. The area to" \ + " process starts at bit *first* from *src*." \ +) + + ret = PyArg_ParseTuple(args, "O&k", convert_to_bitfield, &src, &first); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + or_bit_field_at(bf->native, src, first); + + Py_RETURN_NONE; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * * Description : Détermine si un bit est à 1 dans un champ de bits. * * * * Retour : true si le bit correspondant est à l'état haut. * @@ -695,6 +794,158 @@ static PyObject *py_bitfield_test_all(PyObject *self, PyObject *args) /****************************************************************************** * * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Teste l'état à 0 de bits selon un masque de bits. * +* * +* Retour : true si les bits visés sont à l'état bas. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_zeros_with(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + bitfield_t *mask; /* Champ de bits natif */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + +#define BITFIELD_TEST_ZEROS_WITH_METHOD PYTHON_METHOD_DEF \ +( \ + test_zeros_with, "$self, first, mask, /", \ + METH_VARARGS, py_bitfield, \ + "Test a range of bits against another bit field.\n" \ + "\n" \ + "The area to process starts at bit *first* and the" \ + " test relies on bits set within the *mask* object.\n" \ + "\n" \ + "The result is a boolean value: True if all tested" \ + " bits are unset, False otherwise." \ +) + + ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_zeros_within_bit_field(bf->native, first, mask); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Teste l'état à 1 de bits selon un masque de bits. * +* * +* Retour : true si les bits visés sont à l'état haut. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_test_ones_with(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long first; /* Indice du premier bit testé */ + bitfield_t *mask; /* Champ de bits natif */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + bool status; /* Bilan d'analyse */ + +#define BITFIELD_TEST_ONES_WITH_METHOD PYTHON_METHOD_DEF \ +( \ + test_ones_with, "$self, first, mask, /", \ + METH_VARARGS, py_bitfield, \ + "Test a range of bits against another bit field.\n" \ + "\n" \ + "The area to process starts at bit *first* and the" \ + " test relies on bits set within the *mask* object.\n" \ + "\n" \ + "The result is a boolean value: True if all tested" \ + " bits are set, False otherwise." \ +) + + ret = PyArg_ParseTuple(args, "kO&", &first, convert_to_bitfield, &mask); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + status = test_ones_within_bit_field(bf->native, first, mask); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = champ de bits à consulter. * +* args = arguments fournis pour la conduite de l'opération. * +* * +* Description : Recherche un prochain bit défini dans un champ de bits. * +* * +* Retour : Position d'un bit à 1 ou taille du champ si plus aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_bitfield_find_next_set(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à faire remonter */ + unsigned long prev; /* Indice d'un bit à écarter */ + int ret; /* Bilan de lecture des args. */ + py_bitfield_t *bf; /* Instance à manipuler */ + size_t found; /* Indice de bit trouvé */ + +#define BITFIELD_FIND_NEXT_SET_METHOD PYTHON_METHOD_DEF \ +( \ + find_next_set, "$self, /, prev=None", \ + METH_VARARGS, py_bitfield, \ + "Find the index of the next set bit in the bit field.\n"\ + "\n" \ + "If provided, the *prev* argument is the position of" \ + " a previously found bit, which gets discarded for the" \ + " current call.\n" \ + "\n" \ + "The result is a integer value: a valid index inside" \ + " the bit field, or the bit field size if no set bit" \ + " is found." \ +) + + prev = (unsigned long)-1; + + ret = PyArg_ParseTuple(args, "|k", &prev); + if (!ret) return NULL; + + bf = (py_bitfield_t *)self; + + found = find_next_set_in_bit_field(bf->native, prev == (unsigned long)-1 ? NULL : (size_t []) { prev }); + + result = PyLong_FromSize_t(found); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : self = classe représentant une instruction. * * closure = adresse non utilisée ici. * * * @@ -791,13 +1042,18 @@ PyTypeObject *get_python_bitfield_type(void) static PyMethodDef py_bitfield_methods[] = { BITFIELD_DUP_METHOD, + BITFIELD_RESIZE_METHOD, BITFIELD_RESET_ALL_METHOD, BITFIELD_SET_ALL_METHOD, BITFIELD_RESET_METHOD, BITFIELD_SET_METHOD, + BITFIELD_OR_AT_METHOD, BITFIELD_TEST_METHOD, BITFIELD_TEST_NONE_METHOD, BITFIELD_TEST_ALL_METHOD, + BITFIELD_TEST_ZEROS_WITH_METHOD, + BITFIELD_TEST_ONES_WITH_METHOD, + BITFIELD_FIND_NEXT_SET_METHOD, { NULL } }; @@ -876,6 +1132,51 @@ bool ensure_python_bitfield_is_registered(void) /****************************************************************************** * * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en champ de bits. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_bitfield(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_bitfield_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to bit field"); + break; + + case 1: + *((bitfield_t **)dst) = ((py_bitfield_t *)arg)->native; + break; + + default: + assert(false); + break; + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : field = structure interne à copier en objet Python. * * * * Description : Convertit une structure de type 'bitfield_t' en objet Python.* diff --git a/plugins/pychrysalide/common/bits.h b/plugins/pychrysalide/common/bits.h index 6ddaaa5..804c3b5 100644 --- a/plugins/pychrysalide/common/bits.h +++ b/plugins/pychrysalide/common/bits.h @@ -40,6 +40,9 @@ PyTypeObject *get_python_bitfield_type(void); /* Prend en charge l'objet 'pychrysalide.common.BitField'. */ bool ensure_python_bitfield_is_registered(void); +/* Tente de convertir en champ de bits. */ +int convert_to_bitfield(PyObject *, void *); + /* Convertit une structure de type 'bitfield_t' en objet Python. */ PyObject *build_from_internal_bitfield(const bitfield_t *); diff --git a/plugins/pychrysalide/common/itoa.c b/plugins/pychrysalide/common/itoa.c new file mode 100644 index 0000000..107b047 --- /dev/null +++ b/plugins/pychrysalide/common/itoa.c @@ -0,0 +1,124 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * itoa.c - équivalent Python du fichier "common/itoa.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "itoa.h" + + +#include <common/itoa.h> + + +#include "../access.h" +#include "../helpers.h" + + + +/* Détermine l'empreinte Itoa d'une chaîne de caractères. */ +static PyObject *py_itoa(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = NULL car méthode statique. * +* args = arguments fournis lors de l'appel à la fonction. * +* * +* Description : Convertit une valeur en une forme textuelle. * +* * +* Retour : Chaîne de caractères mises en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_itoa(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + long long n; /* Valeur à transformer */ + unsigned char base; /* Base de travail */ + int ret; /* Bilan de lecture des args. */ + char *strval; /* Valeur sous forme de chaîne */ + +#define ITOA_METHOD PYTHON_METHOD_DEF \ +( \ + itoa, "n, /, base=10", \ + METH_VARARGS, py, \ + "Construct a string representation of an integer *n* according" \ + " to a given *base*.\n" \ + "\n" \ + "Both arguments are expected to be integer values; the result" \ + " is a string or None in case of failure." \ +) + + base = 10; + + ret = PyArg_ParseTuple(args, "L|b", &n, &base); + if (!ret) return NULL; + + strval = itoa(n, base); + + if (strval != NULL) + { + result = PyUnicode_FromString(strval); + free(strval); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'common' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_common_module_with_itoa(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_itoa_methods[] = { + ITOA_METHOD, + { NULL } + }; + + module = get_access_to_python_module("pychrysalide.common"); + + result = register_python_module_methods(module, py_itoa_methods); + + return result; + +} diff --git a/plugins/pychrysalide/common/itoa.h b/plugins/pychrysalide/common/itoa.h new file mode 100644 index 0000000..a66e767 --- /dev/null +++ b/plugins/pychrysalide/common/itoa.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * itoa.h - prototypes pour l'équivalent Python du fichier "common/itoa.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H +#define _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit une extension du module 'common' à compléter. */ +bool populate_common_module_with_itoa(void); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_COMMON_ITOA_H */ diff --git a/plugins/pychrysalide/common/leb128.c b/plugins/pychrysalide/common/leb128.c index 8e1bf28..8b15303 100644 --- a/plugins/pychrysalide/common/leb128.c +++ b/plugins/pychrysalide/common/leb128.c @@ -69,7 +69,7 @@ static PyObject *py_leb128_pack_uleb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ uleb128_t value; /* Valeur à manipuler */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ bool status; /* Bilan de l'opération */ @@ -117,7 +117,7 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ leb128_t value; /* Valeur à manipuler */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ bool status; /* Bilan de l'opération */ @@ -164,7 +164,7 @@ static PyObject *py_leb128_pack_leb128(PyObject *self, PyObject *args) static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ uleb128_t value; /* Valeur à manipuler */ bool status; /* Bilan de l'opération */ @@ -218,9 +218,9 @@ static PyObject *py_leb128_unpack_uleb128(PyObject *self, PyObject *args) static PyObject *py_leb128_unpack_leb128(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ - packed_buffer *pbuf; /* Tampon de données à employer*/ + packed_buffer_t *pbuf; /* Tampon de données à employer*/ int ret; /* Bilan de lecture des args. */ - leb128_t value; /* Valeur à manipuler */ + leb128_t value; /* Valeur à manipuler */ bool status; /* Bilan de l'opération */ #define LEB128_UNPACK_LEB128_METHOD PYTHON_METHOD_DEF \ diff --git a/plugins/pychrysalide/common/module.c b/plugins/pychrysalide/common/module.c index 6ced1b7..a0042ee 100644 --- a/plugins/pychrysalide/common/module.c +++ b/plugins/pychrysalide/common/module.c @@ -28,6 +28,7 @@ #include "bits.h" #include "fnv1a.h" #include "hex.h" +#include "itoa.h" #include "leb128.h" #include "packed.h" #include "pathname.h" @@ -99,6 +100,7 @@ bool populate_common_module(void) if (result) result = populate_common_module_with_fnv1a(); if (result) result = populate_common_module_with_hex(); + if (result) result = populate_common_module_with_itoa(); if (result) result = populate_common_module_with_leb128(); if (result) result = populate_common_module_with_pathname(); if (result) result = populate_common_module_with_pearson(); diff --git a/plugins/pychrysalide/core.c b/plugins/pychrysalide/core.c index 98f94b6..08f570f 100644 --- a/plugins/pychrysalide/core.c +++ b/plugins/pychrysalide/core.c @@ -21,6 +21,11 @@ */ +#undef NO_IMPORT_PYGOBJECT +#include <pygobject.h> +#define NO_IMPORT_PYGOBJECT + + #include "core.h" @@ -35,7 +40,6 @@ #include <unistd.h> -#include <config.h> #include <i18n.h> #include <gleak.h> #include <common/cpp.h> @@ -60,8 +64,10 @@ #include "debug/module.h" #include "format/module.h" #include "glibext/module.h" -#include "gtkext/module.h" -#include "gui/module.h" +#ifdef INCLUDE_GTK_SUPPORT +# include "gtkext/module.h" +# include "gui/module.h" +#endif #include "mangling/module.h" #include "plugins/module.h" #include "plugins/plugin.h" @@ -80,9 +86,6 @@ static bool _standalone = true; /* Réceptacle pour le chargement forcé */ static PyObject *_chrysalide_module = NULL; -/* Conservation des informations du thread principal */ -static PyThreadState *_main_tstate = NULL; - /* Fournit la révision du programme global. */ static PyObject *py_chrysalide_revision(PyObject *, PyObject *); @@ -96,8 +99,13 @@ static PyObject *py_chrysalide_mod_version(PyObject *, PyObject *); /* Détermine si l'interpréteur lancé est celui pris en compte. */ static bool is_current_abi_suitable(void); +/* Assure une pleine initialisation des objets de Python-GI. */ +static bool install_metaclass_for_python_gobjects(void); + /* Définit la version attendue de GTK à charger dans Python. */ +#ifdef INCLUDE_GTK_SUPPORT static bool set_version_for_gtk_namespace(const char *); +#endif /* Point de sortie pour l'initialisation de Python. */ static void PyExit_pychrysalide(void); @@ -249,7 +257,8 @@ static bool is_current_abi_suitable(void) #define GRAB_ABI_FLAGS_IN_PYTHON \ "import sys" "\n" \ "import os" "\n" \ - "os.write(%d, bytes(sys.abiflags, 'UTF-8'))" "\n" + "data = bytes(sys.abiflags, 'UTF-8') + b'\\0'" "\n" \ + "os.write(%d, data)" "\n" result = false; @@ -289,6 +298,126 @@ static bool is_current_abi_suitable(void) /****************************************************************************** * * +* Paramètres : - * +* * +* Description : Assure une pleine initialisation des objets de Python-GI. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool install_metaclass_for_python_gobjects(void) +{ + bool result; /* Bilan à retourner */ + PyObject *gi_types_mod; /* Module Python-GObject */ + + /** + * Les extensions Python sont chargées à partir de la fonction load_python_plugins(), + * qui fait appel à create_python_plugin(). Une instance y est construite via un + * appel à PyObject_CallFunction() avec la classe spécifiée par l'alias AutoLoad + * dans le fichier __init__.py présent dans chaque module d'extension. + * + * Le constructeur py_plugin_module_new() renvoie in fine à la fonction générique + * python_abstract_constructor_with_dynamic_gtype(), laquelle conduit à la fonction + * pygobject_register_class() définie dans <python3-gi>/gi/pygobject-object.c. + * Le code de cette dernière comprend notamment la portion suivante : + * + * [...] + * Py_SET_TYPE(type, PyGObject_MetaType); + * [...] + * if (PyType_Ready(type) < 0) { + * g_warning ("couldn't make the type `%s' ready", type->tp_name); + * return; + * } + * [...] + * + * La fonction PyType_Ready() est définie dans <python3>/Objects/typeobject.c + * et commence par : + * + * int PyType_Ready(PyTypeObject *type) + * { + * if (type->tp_flags & Py_TPFLAGS_READY) { + * assert(_PyType_CheckConsistency(type)); + * return 0; + * } + * [...] + * } + * + * La vérification de cohérencce commence par analyser le type et son propre + * type : + * + * - cf. _PyType_CheckConsistency() dans <python3>/Objects/typeobject.c : + * + * int _PyType_CheckConsistency(PyTypeObject *type) + * { + * [...] + * CHECK(!_PyObject_IsFreed((PyObject *)type)); + * [...] + * } + * + * - cf. _PyObject_IsFreed() dans <python3>/Objects/object.c : + * + * int _PyObject_IsFreed(PyObject *op) + * { + * if (_PyMem_IsPtrFreed(op) || _PyMem_IsPtrFreed(Py_TYPE(op))) { + * return 1; + * } + * + * La fonction _PyMem_IsPtrFreed() recherche entre autres la valeur NULL. + * + * Or le type du type est écrasé dans la fonction pygobject_register_class() + * avec la valeur de la variable PyGObject_MetaType. Cette variable n'est + * définie qu'à un seul endroit, dans <python3-gi>/gi/gimodule.c : + * + * static PyObject * + * pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass) + * { + * Py_INCREF(metaclass); + * PyGObject_MetaType = metaclass; + * Py_INCREF(metaclass); + * + * Py_SET_TYPE(&PyGObject_Type, metaclass); + * + * Py_INCREF(Py_None); + * return Py_None; + * } + * + * Afin de valider la vérification de _PyType_CheckConsistency() pour les + * modules externes qui entraînent un enregistrement tout en portant le drapeau + * Py_TPFLAGS_READY (typiquement ceux du répertoire "plugins/python/", il faut + * initialiser au besoin la variable PyGObject_MetaType. + * + * Une ligne suffit donc à enregistrer le type intermédiaire : + * + * from _gi import types + * + * On simule ici une déclaration similaire si nécessaire + */ + + result = false; + + if (PyType_CheckExact(&PyGObject_Type)) + { + gi_types_mod = PyImport_ImportModule("gi.types"); + + result = (PyErr_Occurred() == NULL); + + if (result) + result = (PyType_CheckExact(&PyGObject_Type) == 0); + + Py_XDECREF(gi_types_mod); + + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : version = idenfiant de la version de GTK à stipuler. * * * * Description : Définit la version attendue de GTK à charger dans Python. * @@ -298,7 +427,7 @@ static bool is_current_abi_suitable(void) * Remarques : - * * * ******************************************************************************/ - +#ifdef INCLUDE_GTK_SUPPORT static bool set_version_for_gtk_namespace(const char *version) { bool result; /* Bilan à retourner */ @@ -334,6 +463,7 @@ static bool set_version_for_gtk_namespace(const char *version) return result; } +#endif /****************************************************************************** @@ -456,8 +586,13 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) goto exit; } + if (!install_metaclass_for_python_gobjects()) + goto exit; + +#ifdef INCLUDE_GTK_SUPPORT if (!set_version_for_gtk_namespace("3.0")) goto exit; +#endif if (!load_all_core_components(true)) { @@ -482,8 +617,10 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) if (status) status = add_debug_module(result); if (status) status = add_format_module(result); if (status) status = add_glibext_module(result); +#ifdef INCLUDE_GTK_SUPPORT if (status) status = add_gtkext_module(result); if (status) status = add_gui_module(result); +#endif if (status) status = add_mangling_module(result); if (status) status = add_plugins_module(result); @@ -497,8 +634,10 @@ PyMODINIT_FUNC PyInit_pychrysalide(void) if (status) status = populate_debug_module(); if (status) status = populate_format_module(); if (status) status = populate_glibext_module(); +#ifdef INCLUDE_GTK_SUPPORT if (status) status = populate_gtkext_module(); if (status) status = populate_gui_module(); +#endif if (status) status = populate_mangling_module(); if (status) status = populate_plugins_module(); @@ -650,7 +789,6 @@ static void load_python_plugins(GPluginModule *plugin) struct dirent *entry; /* Elément trouvé */ char *modname; /* Nom du module pour Python */ char *filename; /* Chemin d'accès reconstruit */ - PyThreadState *tstate; /* Contexte d'environnement */ GPluginModule *pyplugin; /* Lien vers un grffon Python */ bool status; /* Bilan d'une opération */ GGenConfig *config; /* Configuration à charger */ @@ -669,11 +807,11 @@ static void load_python_plugins(GPluginModule *plugin) if (dir != NULL) { - closedir(dir); + closedir(dir); - edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python"); - extend_python_path(edir); - free(edir); + edir = get_effective_directory(PLUGINS_DATA_DIR G_DIR_SEPARATOR_S "python"); + extend_python_path(edir); + free(edir); } @@ -690,7 +828,7 @@ static void load_python_plugins(GPluginModule *plugin) save = NULL; /* gcc... */ for (path = strtok_r(paths, ":", &save); - path != NULL; + path != NULL; path = strtok_r(NULL, ":", &save)) { dir = opendir(path); @@ -730,16 +868,7 @@ static void load_python_plugins(GPluginModule *plugin) filename = stradd(filename, G_DIR_SEPARATOR_S); filename = stradd(filename, entry->d_name); - if (!_standalone) - { - tstate = get_pychrysalide_main_tstate(); - PyEval_RestoreThread(tstate); - } - - pyplugin = g_python_plugin_new(modname, filename); - - if (!_standalone) - PyEval_SaveThread(); + pyplugin = create_python_plugin(modname, filename); if (pyplugin == NULL) { @@ -778,7 +907,7 @@ static void load_python_plugins(GPluginModule *plugin) } - closedir(dir); + closedir(dir); } @@ -802,6 +931,7 @@ static void load_python_plugins(GPluginModule *plugin) G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) { bool result; /* Bilan à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ int ret; /* Bilan de préparatifs */ _standalone = false; @@ -819,9 +949,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) Py_Initialize(); - PyEval_InitThreads(); - - PySys_SetArgv(0, (wchar_t *[]) { NULL }); + gstate = PyGILState_Ensure(); _chrysalide_module = PyImport_ImportModule("pychrysalide"); @@ -838,9 +966,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) result = (_chrysalide_module != NULL); - _main_tstate = PyThreadState_Get(); - - PyEval_ReleaseLock(); + PyGILState_Release(gstate); cpi_done: @@ -863,10 +989,16 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) G_MODULE_EXPORT void chrysalide_plugin_exit(GPluginModule *plugin) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + + gstate = PyGILState_Ensure(); + clear_all_accesses_to_python_modules(); Py_XDECREF(_chrysalide_module); + PyGILState_Release(gstate); + } @@ -907,8 +1039,8 @@ static void free_native_plugin_type(PyTypeObject *type) G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, PluginAction action) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ size_t count; /* Quantité de greffons chargés*/ - PyTypeObject *parent; /* Type Python pour greffon */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ GPluginModule **list; /* Ensemble de ces greffons */ @@ -918,14 +1050,14 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, int ret; /* Bilan d'un appel */ PyTypeObject *type; /* Nouveau type dynamique */ + gstate = PyGILState_Ensure(); + if (action == PGA_NATIVE_PLUGINS_LOADED) { /* Intégration des greffons natifs en Python */ if (ensure_python_plugin_module_is_registered()) { - parent = get_python_plugin_module_type(); - module = get_access_to_python_module("pychrysalide.plugins"); assert(module != NULL); @@ -958,7 +1090,7 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, type->tp_flags = Py_TPFLAGS_DEFAULT; type->tp_new = no_python_constructor_allowed; - if (register_class_for_pygobject(dict, G_OBJECT_TYPE(list[i]), type, parent)) + if (register_class_for_pygobject(dict, G_OBJECT_TYPE(list[i]), type)) g_object_set_data_full(G_OBJECT(list[i]), "python_type", type, (GDestroyNotify)free_native_plugin_type); @@ -978,6 +1110,8 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, } + PyGILState_Release(gstate); + } @@ -998,17 +1132,13 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *plugin, G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *plugin, PluginAction action, GType type) { gpointer result; /* Instance à retourner */ - PyThreadState *tstate; /* Contexte d'environnement */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyTypeObject *pytype; /* Classe Python concernée */ PyObject *instance; /* Initialisation forcée */ result = NULL; - if (!_standalone) - { - tstate = get_pychrysalide_main_tstate(); - PyEval_RestoreThread(tstate); - } + gstate = PyGILState_Ensure(); pytype = pygobject_lookup_class(type); @@ -1021,31 +1151,7 @@ G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *pl } - if (!_standalone) - PyEval_SaveThread(); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Fournit les informations du thread principal. * -* * -* Retour : Indications utiles à Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PyThreadState *get_pychrysalide_main_tstate(void) -{ - PyThreadState *result; /* Indications à retourner */ - - result = _main_tstate; + PyGILState_Release(gstate); return result; @@ -1074,6 +1180,8 @@ void log_pychrysalide_exception(const char *prefix, ...) PyObject *err_string; /* Description Python d'erreur */ const char *err_msg; /* Représentation humaine */ + assert(PyGILState_Check() == 1); + if (PyErr_Occurred()) { /* Base de la communication */ @@ -1120,7 +1228,7 @@ void log_pychrysalide_exception(const char *prefix, ...) * * C'est par exemple le cas quand un greffon Python ne peut se lancer * correctement ; l'exception est alors levée à partir de la fonction - * g_python_plugin_new() et le plantage intervient en sortie d'exécution, + * create_python_plugin() et le plantage intervient en sortie d'exécution, * au moment de la libération de l'extension Python : * * ==14939== Jump to the invalid address stated on the next line diff --git a/plugins/pychrysalide/core.h b/plugins/pychrysalide/core.h index 6a7b9d1..88c4140 100644 --- a/plugins/pychrysalide/core.h +++ b/plugins/pychrysalide/core.h @@ -55,9 +55,6 @@ G_MODULE_EXPORT void chrysalide_plugin_on_plugins_loaded(GPluginModule *, Plugin /* Crée une instance à partir d'un type dynamique externe. */ G_MODULE_EXPORT gpointer chrysalide_plugin_build_type_instance(GPluginModule *, PluginAction, GType); -/* Fournit les informations du thread principal. */ -PyThreadState *get_pychrysalide_main_tstate(void); - /* Présente dans le journal une exception survenue. */ void log_pychrysalide_exception(const char *, ...); diff --git a/plugins/pychrysalide/core/Makefile.am b/plugins/pychrysalide/core/Makefile.am index 6c032c3..880823d 100644 --- a/plugins/pychrysalide/core/Makefile.am +++ b/plugins/pychrysalide/core/Makefile.am @@ -1,25 +1,20 @@ noinst_LTLIBRARIES = libpychrysacore.la -libpychrysacore_la_SOURCES = \ - constants.h constants.c \ - demanglers.h demanglers.c \ - global.h global.c \ - logs.h logs.c \ - module.h module.c \ - params.h params.c \ - processors.h processors.c \ +libpychrysacore_la_SOURCES = \ + constants.h constants.c \ + demanglers.h demanglers.c \ + global.h global.c \ + logs.h logs.c \ + module.h module.c \ + params.h params.c \ + processors.h processors.c \ queue.h queue.c -libpychrysacore_la_LDFLAGS = +libpychrysacore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysacore_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/core/global.c b/plugins/pychrysalide/core/global.c index ecaf2c6..9632e75 100644 --- a/plugins/pychrysalide/core/global.c +++ b/plugins/pychrysalide/core/global.c @@ -187,6 +187,52 @@ static PyObject *py_global_get_content_resolver(PyObject *self, PyObject *args) * Paramètres : self = objet Python concerné par l'appel. * * args = non utilisé ici. * * * +* Description : Fournit l'adresse de l'espace de noms principal pour ROST. * +* * +* Retour : Espace de noms racine de ROST ou NULL si aucun (!). * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_global_get_rost_root_namespace(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance Python à retourner */ + GScanNamespace *root_ns; /* Espace de noms ROST racine */ + +#define GLOBAL_GET_ROST_ROOT_NAMESPACE_METHOD PYTHON_METHOD_DEF \ +( \ + get_rost_root_namespace, "", \ + METH_NOARGS, py_global, \ + "Get the root namespace for ROST." \ + "\n" \ + "The returned object is a pychrysalide.analysis.scan.ScanNamespace" \ + " instance used as singleton; it should not be *None*." \ +) + + root_ns = get_rost_root_namespace(); + + if (root_ns != NULL) + { + result = pygobject_new(G_OBJECT(root_ns)); + g_object_unref(G_OBJECT(root_ns)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* args = non utilisé ici. * +* * * Description : Fournit l'adresse du projet courant. * * * * Retour : Adresse du résolveur global ou None si aucun. * @@ -289,6 +335,7 @@ bool populate_core_module_with_global(void) GLOBAL_IS_BATCH_MODE_METHOD, GLOBAL_GET_CONTENT_EXPLORER_METHOD, GLOBAL_GET_CONTENT_RESOLVER_METHOD, + GLOBAL_GET_ROST_ROOT_NAMESPACE_METHOD, GLOBAL_GET_CURRENT_PROJECT_METHOD, GLOBAL_SET_CURRENT_PROJECT_METHOD, { NULL } diff --git a/plugins/pychrysalide/core/queue.c b/plugins/pychrysalide/core/queue.c index d0fbed8..febf1b0 100644 --- a/plugins/pychrysalide/core/queue.c +++ b/plugins/pychrysalide/core/queue.c @@ -63,7 +63,6 @@ static PyObject *py_queue_wait_for_all_global_works(PyObject *, PyObject *); static PyObject *py_queue_setup_global_work_group(PyObject *self, PyObject *args) { PyObject *result; /* Valeur à retourner */ - PyThreadState *_save; /* Sauvegarde de contexte */ wgroup_id_t wid; /* Identifiant de groupe */ #define QUEUE_SETUP_GLOBAL_WORK_GROUP_METHOD PYTHON_METHOD_DEF \ @@ -79,14 +78,10 @@ static PyObject *py_queue_setup_global_work_group(PyObject *self, PyObject *args " unique identifier of a work group." \ ) - Py_UNBLOCK_THREADS; - wid = setup_global_work_group(); result = PyLong_FromUnsignedLongLong(wid); - Py_BLOCK_THREADS; - return result; } @@ -109,8 +104,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject { PyObject *result; /* Valeur à retourner */ unsigned int count; /* Nombre de thread parallèle */ - PyThreadState *_save; /* Sauvegarde de contexte */ - int ret; /* Bilan de lecture des args. */ wgroup_id_t wid; /* Identifiant de groupe */ @@ -131,8 +124,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject count = 1; - Py_UNBLOCK_THREADS; - ret = PyArg_ParseTuple(args, "|I", &count); if (!ret) goto exit; @@ -148,8 +139,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject exit: - Py_BLOCK_THREADS; - return result; } @@ -170,8 +159,6 @@ static PyObject *py_queue_setup_tiny_global_work_group(PyObject *self, PyObject static PyObject *py_queue_wait_for_all_global_works(PyObject *self, PyObject *args) { - PyThreadState *_save; /* Sauvegarde de contexte */ - #define QUEUE_WAIT_FOR_ALL_GLOBAL_WORKS_METHOD PYTHON_METHOD_DEF \ ( \ wait_for_all_global_works, "", \ @@ -179,12 +166,8 @@ static PyObject *py_queue_wait_for_all_global_works(PyObject *self, PyObject *ar "Wait for all global tasks being processed." \ ) - Py_UNBLOCK_THREADS; - wait_for_all_global_works(); - Py_BLOCK_THREADS; - Py_RETURN_NONE; } diff --git a/plugins/pychrysalide/debug/Makefile.am b/plugins/pychrysalide/debug/Makefile.am index 4bd8e78..c653a6d 100644 --- a/plugins/pychrysalide/debug/Makefile.am +++ b/plugins/pychrysalide/debug/Makefile.am @@ -1,23 +1,14 @@ noinst_LTLIBRARIES = libpychrysadebug.la -libpychrysadebug_la_SOURCES = \ - debugger.h debugger.c \ +libpychrysadebug_la_SOURCES = \ + debugger.h debugger.c \ module.h module.c -libpychrysadebug_la_LIBADD = - -libpychrysadebug_la_LDFLAGS = +libpychrysadebug_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysadebug_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/debug/debugger.c b/plugins/pychrysalide/debug/debugger.c index e65e295..b21087d 100644 --- a/plugins/pychrysalide/debug/debugger.c +++ b/plugins/pychrysalide/debug/debugger.c @@ -1195,7 +1195,7 @@ bool ensure_python_binary_debugger_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BINARY_DEBUGGER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BINARY_DEBUGGER, type)) return false; } diff --git a/plugins/pychrysalide/format/Makefile.am b/plugins/pychrysalide/format/Makefile.am index 68eb3be..337265d 100644 --- a/plugins/pychrysalide/format/Makefile.am +++ b/plugins/pychrysalide/format/Makefile.am @@ -1,30 +1,22 @@ noinst_LTLIBRARIES = libpychrysaformat.la -libpychrysaformat_la_SOURCES = \ - constants.h constants.c \ - executable.h executable.c \ - flat.h flat.c \ - format.h format.c \ - known.h known.c \ - module.h module.c \ - strsym.h strsym.c \ - symbol.h symbol.c \ +libpychrysaformat_la_SOURCES = \ + constants.h constants.c \ + executable.h executable.c \ + flat.h flat.c \ + format.h format.c \ + known.h known.c \ + module.h module.c \ + preload.h preload.c \ + strsym.h strsym.c \ + symbol.h symbol.c \ symiter.h symiter.c -libpychrysaformat_la_LIBADD = - -libpychrysaformat_la_LDFLAGS = +libpychrysaformat_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaformat_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/format/executable.c b/plugins/pychrysalide/format/executable.c index ac0125d..ff2d14a 100644 --- a/plugins/pychrysalide/format/executable.c +++ b/plugins/pychrysalide/format/executable.c @@ -268,7 +268,7 @@ bool ensure_python_executable_format_is_registered(void) if (!ensure_python_binary_format_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_EXE_FORMAT, type, get_python_binary_format_type())) + if (!register_class_for_pygobject(dict, G_TYPE_EXE_FORMAT, type)) return false; } diff --git a/plugins/pychrysalide/format/flat.c b/plugins/pychrysalide/format/flat.c index 2c8e9fd..4df3646 100644 --- a/plugins/pychrysalide/format/flat.c +++ b/plugins/pychrysalide/format/flat.c @@ -173,7 +173,7 @@ bool ensure_python_flat_format_is_registered(void) if (!ensure_python_executable_format_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_FLAT_FORMAT, type, get_python_executable_format_type())) + if (!register_class_for_pygobject(dict, G_TYPE_FLAT_FORMAT, type)) return false; } diff --git a/plugins/pychrysalide/format/format.c b/plugins/pychrysalide/format/format.c index 66d346c..82c6c33 100644 --- a/plugins/pychrysalide/format/format.c +++ b/plugins/pychrysalide/format/format.c @@ -166,7 +166,7 @@ static PyObject *py_binary_format_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1150,7 +1150,7 @@ bool ensure_python_binary_format_is_registered(void) if (!ensure_python_known_format_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type, get_python_known_format_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_FORMAT, type)) return false; if (!define_binary_format_constants(type)) diff --git a/plugins/pychrysalide/format/known.c b/plugins/pychrysalide/format/known.c index a2fc18c..3167ba2 100644 --- a/plugins/pychrysalide/format/known.c +++ b/plugins/pychrysalide/format/known.c @@ -132,7 +132,7 @@ static PyObject *py_known_format_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -789,7 +789,7 @@ bool ensure_python_known_format_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_FORMAT, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_KNOWN_FORMAT, type)) return false; } diff --git a/plugins/pychrysalide/format/module.c b/plugins/pychrysalide/format/module.c index 52dc58b..62c15ed 100644 --- a/plugins/pychrysalide/format/module.c +++ b/plugins/pychrysalide/format/module.c @@ -32,6 +32,7 @@ #include "flat.h" #include "format.h" #include "known.h" +#include "preload.h" #include "strsym.h" #include "symbol.h" #include "symiter.h" @@ -105,6 +106,7 @@ bool populate_format_module(void) if (result) result = ensure_python_flat_format_is_registered(); if (result) result = ensure_python_known_format_is_registered(); if (result) result = ensure_python_binary_format_is_registered(); + if (result) result = ensure_python_preload_info_is_registered(); if (result) result = ensure_python_string_symbol_is_registered(); if (result) result = ensure_python_binary_symbol_is_registered(); if (result) result = ensure_python_sym_iterator_is_registered(); diff --git a/plugins/pychrysalide/format/preload.c b/plugins/pychrysalide/format/preload.c new file mode 100644 index 0000000..e4f2a9c --- /dev/null +++ b/plugins/pychrysalide/format/preload.c @@ -0,0 +1,207 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * preload.c - équivalent Python du fichier "format/preload.c" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "preload.h" + + +#include <pygobject.h> + + +#include <format/preload-int.h> + + +#include "../access.h" +#include "../helpers.h" + + + +CREATE_DYN_CONSTRUCTOR(preload_info, G_TYPE_PRELOAD_INFO); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_preload_info_init(PyObject *, PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_preload_info_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan d'initialisation */ + +#define PRELOAD_INFO_DOC \ + "The PreloadInfo object stores all kinds of disassembling" \ + " information available from the analysis of a file format" \ + " itsself.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " PreloadInfo()" + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_preload_info_type(void) +{ + static PyMethodDef py_preload_info_methods[] = { + { NULL } + }; + + static PyGetSetDef py_preload_info_getseters[] = { + { NULL } + }; + + static PyTypeObject py_preload_info_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.format.PreloadInfo", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = PRELOAD_INFO_DOC, + + .tp_methods = py_preload_info_methods, + .tp_getset = py_preload_info_getseters, + + .tp_init = py_preload_info_init, + .tp_new = py_preload_info_new, + + }; + + return &py_preload_info_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.format.PreloadInfo'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_preload_info_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ArchContext' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_preload_info_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.format"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_PRELOAD_INFO, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en espace de préchargement. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_preload_info(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_preload_info_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to disassembly context"); + break; + + case 1: + *((GPreloadInfo **)dst) = G_PRELOAD_INFO(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/format/preload.h b/plugins/pychrysalide/format/preload.h new file mode 100644 index 0000000..bf33e82 --- /dev/null +++ b/plugins/pychrysalide/format/preload.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * preload.h - prototypes pour l'équivalent Python du fichier "format/preload.h" + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H +#define _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_preload_info_type(void); + +/* Prend en charge l'objet 'pychrysalide.format.PreloadInfo'. */ +bool ensure_python_preload_info_is_registered(void); + +/* Tente de convertir en espace de préchargement. */ +int convert_to_preload_info(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_FORMAT_PRELOAD_H */ diff --git a/plugins/pychrysalide/format/strsym.c b/plugins/pychrysalide/format/strsym.c index c85d61f..adc0e48 100644 --- a/plugins/pychrysalide/format/strsym.c +++ b/plugins/pychrysalide/format/strsym.c @@ -119,7 +119,7 @@ static PyObject *py_string_symbol_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -501,7 +501,7 @@ bool ensure_python_string_symbol_is_registered(void) if (!ensure_python_binary_symbol_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_STR_SYMBOL, type, get_python_binary_symbol_type())) + if (!register_class_for_pygobject(dict, G_TYPE_STR_SYMBOL, type)) return false; if (!define_string_symbol_constants(type)) diff --git a/plugins/pychrysalide/format/symbol.c b/plugins/pychrysalide/format/symbol.c index d6d6402..d3a9c1e 100644 --- a/plugins/pychrysalide/format/symbol.c +++ b/plugins/pychrysalide/format/symbol.c @@ -43,6 +43,7 @@ #include "../helpers.h" #include "../analysis/routine.h" #include "../analysis/db/items/comment.h" +#include "../analysis/storage/serialize.h" #include "../arch/instruction.h" #include "../arch/vmpa.h" #include "../glibext/linegen.h" @@ -156,7 +157,7 @@ static PyObject *py_binary_symbol_new(PyTypeObject *type, PyObject *args, PyObje if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -214,6 +215,7 @@ static void py_binary_symbol_init_gclass(GBinSymbolClass *class, gpointer unused static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *symbol) { char *result; /* Etiquette à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ PyObject *pyret; /* Bilan de consultation */ @@ -228,6 +230,8 @@ static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *symbol) result = NULL; + gstate = PyGILState_Ensure(); + pyobj = pygobject_new(G_OBJECT(symbol)); if (has_python_method(pyobj, "_get_label")) @@ -246,6 +250,8 @@ static char *py_binary_symbol_get_label_wrapper(const GBinSymbol *symbol) Py_DECREF(pyobj); + PyGILState_Release(gstate); + return result; } @@ -973,7 +979,10 @@ bool ensure_python_binary_symbol_is_registered(void) if (!ensure_python_line_generator_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BIN_SYMBOL, type, &PyGObject_Type)) + if (!ensure_python_serializable_object_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_BIN_SYMBOL, type)) return false; if (!define_binary_symbol_constants(type)) diff --git a/plugins/pychrysalide/glibext/Makefile.am b/plugins/pychrysalide/glibext/Makefile.am index 179a991..2ed2aa5 100644 --- a/plugins/pychrysalide/glibext/Makefile.am +++ b/plugins/pychrysalide/glibext/Makefile.am @@ -1,29 +1,32 @@ noinst_LTLIBRARIES = libpychrysaglibext.la -libpychrysaglibext_la_SOURCES = \ - constants.h constants.c \ - binarycursor.h binarycursor.c \ - binportion.h binportion.c \ - buffercache.h buffercache.c \ - bufferline.h bufferline.c \ - bufferview.h bufferview.c \ - configuration.h configuration.c \ - linecursor.h linecursor.c \ - linegen.h linegen.c \ - loadedpanel.h loadedpanel.c \ - module.h module.c \ +libpychrysaglibext_la_SOURCES = \ + constants.h constants.c \ + binarycursor.h binarycursor.c \ + binportion.h binportion.c \ + buffercache.h buffercache.c \ + bufferline.h bufferline.c \ + comparison.h comparison.c \ + configuration.h configuration.c \ + linecursor.h linecursor.c \ + linegen.h linegen.c \ + module.h module.c \ + singleton.h singleton.c + +if BUILD_GTK_SUPPORT + +libpychrysaglibext_la_SOURCES += \ + bufferview.h bufferview.c \ + loadedpanel.h loadedpanel.c \ named.h named.c -libpychrysaglibext_la_LDFLAGS = +endif + +libpychrysaglibext_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaglibext_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/glibext/binarycursor.c b/plugins/pychrysalide/glibext/binarycursor.c index 4da040a..91dce3e 100644 --- a/plugins/pychrysalide/glibext/binarycursor.c +++ b/plugins/pychrysalide/glibext/binarycursor.c @@ -321,7 +321,7 @@ bool ensure_python_binary_cursor_is_registered(void) if (!ensure_python_line_cursor_is_registered()) return false; - if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type, get_python_line_cursor_type())) + if (!register_class_for_pygobject(dict, G_TYPE_BINARY_CURSOR, type)) return false; } diff --git a/plugins/pychrysalide/glibext/binportion.c b/plugins/pychrysalide/glibext/binportion.c index 060f001..70eb314 100644 --- a/plugins/pychrysalide/glibext/binportion.c +++ b/plugins/pychrysalide/glibext/binportion.c @@ -112,7 +112,7 @@ static PyObject *py_bin_portion_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -674,7 +674,7 @@ bool ensure_python_binary_portion_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BIN_PORTION, type)) return false; if (!define_binary_portion_constants(type)) diff --git a/plugins/pychrysalide/glibext/buffercache.c b/plugins/pychrysalide/glibext/buffercache.c index 0cf3342..03301d6 100644 --- a/plugins/pychrysalide/glibext/buffercache.c +++ b/plugins/pychrysalide/glibext/buffercache.c @@ -88,9 +88,13 @@ static PyObject *py_buffer_cache_get_line_flags(PyObject *, PyObject *); /* Retire une propriété particulière attachée à une ligne. */ static PyObject *py_buffer_cache_remove_line_flag(PyObject *, PyObject *); +#ifdef INCLUDE_GTK_SUPPORT + /* Retrouve une ligne au sein d'un tampon avec un indice. */ static PyObject *py_buffer_cache_find_line_by_index(PyObject *, PyObject *); +#endif + /* Avance autant que possible vers une ligne idéale. */ static PyObject *py_buffer_cache_look_for_flag(PyObject *, PyObject *); @@ -153,7 +157,7 @@ static PyObject *py_buffer_cache_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -825,6 +829,9 @@ static PyObject *py_buffer_cache_remove_line_flag(PyObject *self, PyObject *args } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : self = classe représentant un tampon de code. * @@ -883,6 +890,9 @@ static PyObject *py_buffer_cache_find_line_by_index(PyObject *self, PyObject *ar } +#endif + + /****************************************************************************** * * * Paramètres : self = classe représentant un tampon de code. * @@ -1157,7 +1167,9 @@ PyTypeObject *get_python_buffer_cache_type(void) BUFFER_CACHE_ADD_LINE_FLAG_METHOD, BUFFER_CACHE_GET_LINE_FLAGS_METHOD, BUFFER_CACHE_REMOVE_LINE_FLAG_METHOD, +#ifdef INCLUDE_GTK_SUPPORT BUFFER_CACHE_FIND_LINE_BY_INDEX_METHOD, +#endif BUFFER_CACHE_LOOK_FOR_FLAG_METHOD, { NULL } }; @@ -1221,7 +1233,7 @@ bool ensure_python_buffer_cache_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_CACHE, type)) return false; } diff --git a/plugins/pychrysalide/glibext/bufferline.c b/plugins/pychrysalide/glibext/bufferline.c index c88fe7f..09404bc 100644 --- a/plugins/pychrysalide/glibext/bufferline.c +++ b/plugins/pychrysalide/glibext/bufferline.c @@ -106,7 +106,7 @@ static PyObject *py_buffer_line_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -339,7 +339,7 @@ bool ensure_python_buffer_line_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_LINE, type)) return false; if (!define_line_segment_constants(type)) diff --git a/plugins/pychrysalide/glibext/bufferview.c b/plugins/pychrysalide/glibext/bufferview.c index 98cc10a..d4cbdc2 100644 --- a/plugins/pychrysalide/glibext/bufferview.c +++ b/plugins/pychrysalide/glibext/bufferview.c @@ -146,7 +146,7 @@ bool ensure_python_buffer_view_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_BUFFER_VIEW, type)) return false; } diff --git a/plugins/pychrysalide/glibext/comparison.c b/plugins/pychrysalide/glibext/comparison.c new file mode 100644 index 0000000..548f700 --- /dev/null +++ b/plugins/pychrysalide/glibext/comparison.c @@ -0,0 +1,341 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * comparison.c - équivalent Python du fichier "glibext/comparison.h" + * + * Copyright (C) 2018-2019 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "comparison.h" + + +#include <pygobject.h> + + +#include <glibext/comparison-int.h> + + +#include "constants.h" +#include "../access.h" +#include "../helpers.h" +#include "../analysis/content.h" + + + +/* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ + + +/* Procède à l'initialisation de l'interface de comparaison. */ +static void py_comparable_item_interface_init(GComparableItemIface *, gpointer *); + +/* Réalise une comparaison entre objets selon un critère précis. */ +static bool py_comparable_item_compare_rich(const GComparableItem *, const GComparableItem *, RichCmpOperation, bool *); + + + +/* ------------------------- CONNEXION AVEC L'API DE PYTHON ------------------------- */ + + +/* Effectue une comparaison avec un objet 'ComparableItem'. */ +static PyObject *py_comparable_item_richcompare(PyObject *, PyObject *, int); + + + +/* ---------------------------------------------------------------------------------- */ +/* GLUE POUR CREATION DEPUIS PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* unused = adresse non utilisée ici. * +* * +* Description : Procède à l'initialisation de l'interface de comparaison. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_comparable_item_interface_init(GComparableItemIface *iface, gpointer *unused) +{ + +#define COMPARABLE_ITEM_DOC \ + "ComparableItem provides an interface to compare objects.\n" \ + "\n" \ + "A typical class declaration for a new implementation looks like:\n" \ + "\n" \ + " class NewImplem(GObject.Object, ComparableItem):\n" \ + " ...\n" \ + "\n" + + iface->cmp_rich = py_comparable_item_compare_rich; + +} + + +/****************************************************************************** +* * +* Paramètres : item = premier objet à cnsulter pour une comparaison. * +* other = second objet à cnsulter pour une comparaison. * +* op = opération de comparaison à réaliser. * +* status = bilan des opérations de comparaison. [OUT] * +* * +* Description : Réalise une comparaison entre objets selon un critère précis.* +* * +* Retour : true si la comparaison a pu être effectuée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_comparable_item_compare_rich(const GComparableItem *item, const GComparableItem *other, RichCmpOperation op, bool *status) +{ + bool result; /* Etat à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyitem; /* Objet Python concerné #1 */ + PyObject *pyother; /* Objet Python concerné #2 */ + PyObject *pyret; /* Bilan de consultation */ + int ret; /* Bilan d'une conversion */ + + result = false; + + gstate = PyGILState_Ensure(); + + pyitem = pygobject_new(G_OBJECT(item)); + pyother = pygobject_new(G_OBJECT(other)); + + pyret = PyObject_RichCompare(pyitem, pyother, op); + + if (pyret != NULL) + { + ret = PyBool_Check(pyret); + + if (ret) + { + *status = (pyret == Py_True); + result = true; + } + + Py_DECREF(pyret); + + } + + Py_DECREF(pyother); + Py_DECREF(pyitem); + + PyGILState_Release(gstate); + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* CONNEXION AVEC L'API DE PYTHON */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : a = premier object Python à consulter. * +* b = second object Python à consulter. * +* op = type de comparaison menée. * +* * +* Description : Effectue une comparaison avec un objet 'ComparableItem'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_comparable_item_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + int ret; /* Bilan de lecture des args. */ + GComparableItem *item_a; /* Instance à manipuler #1 */ + GComparableItem *item_b; /* Instance à manipuler #2 */ + bool valid; /* Indication de validité */ + bool status; /* Résultat d'une comparaison */ + + ret = PyObject_IsInstance(b, (PyObject *)get_python_comparable_item_type()); + if (!ret) + { + result = Py_NotImplemented; + goto cmp_done; + } + + item_a = G_COMPARABLE_ITEM(pygobject_get(a)); + item_b = G_COMPARABLE_ITEM(pygobject_get(b)); + + valid = g_comparable_item_compare_rich(item_a, item_b, op, &status); + + if (valid) + result = status ? Py_True : Py_False; + else + result = Py_NotImplemented; + + cmp_done: + + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_comparable_item_type(void) +{ + static PyMethodDef py_comparable_item_methods[] = { + { NULL } + }; + + static PyGetSetDef py_comparable_item_getseters[] = { + { NULL } + }; + + static PyTypeObject py_comparable_item_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.glibext.ComparableItem", + .tp_basicsize = sizeof(PyObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = COMPARABLE_ITEM_DOC, + + .tp_richcompare = py_comparable_item_richcompare, + + .tp_methods = py_comparable_item_methods, + .tp_getset = py_comparable_item_getseters, + + }; + + return &py_comparable_item_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.....ComparableItem'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_comparable_item_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'ComparableItem' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + static GInterfaceInfo info = { /* Paramètres d'inscription */ + + .interface_init = (GInterfaceInitFunc)py_comparable_item_interface_init, + .interface_finalize = NULL, + .interface_data = NULL, + + }; + + type = get_python_comparable_item_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.glibext"); + + dict = PyModule_GetDict(module); + + if (!register_interface_for_pygobject(dict, G_TYPE_COMPARABLE_ITEM, type, &info)) + return false; + + if (!define_comparable_item_constants(type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en élément comparable. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_comparable_item(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_comparable_item_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to comparable item"); + break; + + case 1: + *((GComparableItem **)dst) = G_COMPARABLE_ITEM(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/comparison.h b/plugins/pychrysalide/glibext/comparison.h new file mode 100644 index 0000000..79f7092 --- /dev/null +++ b/plugins/pychrysalide/glibext/comparison.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * comparison.h - prototypes pour l'équivalent Python du fichier "glibext/comparison.h" + * + * Copyright (C) 2018 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_comparable_item_type(void); + +/* Prend en charge l'objet 'pychrysalide.glibext.ComparableItem'. */ +bool ensure_python_comparable_item_is_registered(void); + +/* Tente de convertir en élément comparable. */ +int convert_to_comparable_item(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_COMPARISON_H */ diff --git a/plugins/pychrysalide/glibext/configuration.c b/plugins/pychrysalide/glibext/configuration.c index b0586af..c630331 100644 --- a/plugins/pychrysalide/glibext/configuration.c +++ b/plugins/pychrysalide/glibext/configuration.c @@ -174,7 +174,7 @@ static PyObject *py_config_param_new(PyTypeObject *type, PyObject *args, PyObjec if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -733,7 +733,7 @@ bool ensure_python_config_param_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_CFG_PARAM, type)) return false; if (!define_config_param_constants(type)) @@ -1036,7 +1036,7 @@ static PyObject *py_generic_config_new(PyTypeObject *type, PyObject *args, PyObj if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1580,7 +1580,7 @@ bool ensure_python_generic_config_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_GEN_CONFIG, type)) return false; } diff --git a/plugins/pychrysalide/glibext/constants.c b/plugins/pychrysalide/glibext/constants.c index 373d1bf..169ffa2 100644 --- a/plugins/pychrysalide/glibext/constants.c +++ b/plugins/pychrysalide/glibext/constants.c @@ -27,10 +27,13 @@ #include <i18n.h> #include <glibext/bufferline.h> +#include <glibext/comparison.h> #include <glibext/configuration.h> #include <glibext/linesegment.h> #include <glibext/gbinportion.h> -#include <glibext/gloadedpanel.h> +#ifdef INCLUDE_GTK_SUPPORT +# include <glibext/gloadedpanel.h> +#endif #include "../helpers.h" @@ -250,6 +253,48 @@ int convert_to_buffer_line_flags(PyObject *arg, void *dst) * * * Paramètres : type = type dont le dictionnaire est à compléter. * * * +* Description : Définit les constantes relatives aux modes de comparaison. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_comparable_item_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "LT", RCO_LT); + if (result) result = add_const_to_group(values, "LE", RCO_LE); + if (result) result = add_const_to_group(values, "EQ", RCO_EQ); + if (result) result = add_const_to_group(values, "NE", RCO_NE); + if (result) result = add_const_to_group(values, "GT", RCO_GT); + if (result) result = add_const_to_group(values, "GE", RCO_GE); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, true, "RichCmpOperation", values, + "Modes for objects comparison."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * * Description : Définit les constantes relatives aux paramètres de config. * * * * Retour : true en cas de succès de l'opération, false sinon. * @@ -471,6 +516,9 @@ int convert_to_rendering_tag_type(PyObject *arg, void *dst) } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : type = type dont le dictionnaire est à compléter. * @@ -566,3 +614,6 @@ int convert_to_scroll_position_tweak(PyObject *arg, void *dst) return result; } + + +#endif diff --git a/plugins/pychrysalide/glibext/constants.h b/plugins/pychrysalide/glibext/constants.h index 342b7ad..4a4f6da 100644 --- a/plugins/pychrysalide/glibext/constants.h +++ b/plugins/pychrysalide/glibext/constants.h @@ -43,6 +43,9 @@ bool define_buffer_line_constants(PyTypeObject *); /* Tente de convertir en constante BufferLineFlags. */ int convert_to_buffer_line_flags(PyObject *, void *); +/* Définit les constantes relatives aux modes de comparaison. */ +bool define_comparable_item_constants(PyTypeObject *); + /* Définit les constantes relatives aux paramètres de configuration. */ bool define_config_param_constants(PyTypeObject *); @@ -55,12 +58,16 @@ bool define_line_segment_constants(PyTypeObject *); /* Tente de convertir en constante RenderingTagType. */ int convert_to_rendering_tag_type(PyObject *, void *); +#ifdef INCLUDE_GTK_SUPPORT + /* Définit les constantes relatives aux panneaux de chargement. */ bool define_loaded_panel_constants(PyTypeObject *); /* Tente de convertir en constante ScrollPositionTweak. */ int convert_to_scroll_position_tweak(PyObject *, void *); +#endif + #endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_CONSTANTS_H */ diff --git a/plugins/pychrysalide/glibext/linecursor.c b/plugins/pychrysalide/glibext/linecursor.c index 217234a..4ac7f85 100644 --- a/plugins/pychrysalide/glibext/linecursor.c +++ b/plugins/pychrysalide/glibext/linecursor.c @@ -184,7 +184,7 @@ bool ensure_python_line_cursor_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_LINE_CURSOR, type)) return false; } diff --git a/plugins/pychrysalide/glibext/module.c b/plugins/pychrysalide/glibext/module.c index 176d815..3e4307a 100644 --- a/plugins/pychrysalide/glibext/module.c +++ b/plugins/pychrysalide/glibext/module.c @@ -33,11 +33,13 @@ #include "buffercache.h" #include "bufferline.h" #include "bufferview.h" +#include "comparison.h" #include "configuration.h" #include "linecursor.h" #include "linegen.h" #include "loadedpanel.h" #include "named.h" +#include "singleton.h" #include "../helpers.h" @@ -104,18 +106,26 @@ bool populate_glibext_module(void) result = true; + if (result) result = ensure_python_singleton_candidate_is_registered(); + if (result) result = ensure_python_binary_cursor_is_registered(); if (result) result = ensure_python_binary_portion_is_registered(); if (result) result = ensure_python_buffer_cache_is_registered(); if (result) result = ensure_python_buffer_line_is_registered(); +#ifdef INCLUDE_GTK_SUPPORT if (result) result = ensure_python_buffer_view_is_registered(); +#endif + if (result) result = ensure_python_comparable_item_is_registered(); if (result) result = ensure_python_config_param_is_registered(); if (result) result = ensure_python_config_param_iterator_is_registered(); if (result) result = ensure_python_generic_config_is_registered(); if (result) result = ensure_python_line_cursor_is_registered(); if (result) result = ensure_python_line_generator_is_registered(); +#ifdef INCLUDE_GTK_SUPPORT if (result) result = ensure_python_loaded_panel_is_registered(); if (result) result = ensure_python_named_widget_is_registered(); +#endif + if (result) result = ensure_python_singleton_factory_is_registered(); assert(result); diff --git a/plugins/pychrysalide/glibext/singleton.c b/plugins/pychrysalide/glibext/singleton.c new file mode 100644 index 0000000..8491473 --- /dev/null +++ b/plugins/pychrysalide/glibext/singleton.c @@ -0,0 +1,1165 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * singleton.c - équivalent Python du fichier "glibext/singleton.c" + * + * Copyright (C) 2021 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "singleton.h" + + +#include <assert.h> +#include <pygobject.h> + + +#include <glibext/singleton-int.h> +#include <plugins/dt.h> + + +#include "../access.h" +#include "../helpers.h" + + + +/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */ + + +/* Procède à l'initialisation de l'interface de candidature. */ +static void py_singleton_candidate_interface_init(GSingletonCandidateIface *, gpointer *); + +/* Fournit une liste de candidats embarqués par un candidat. */ +static GSingletonCandidate **py_singleton_candidate_list_inner_instances_wrapper(const GSingletonCandidate *, size_t *); + +/* Met à jour une liste de candidats embarqués par un candidat. */ +static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCandidate *, GSingletonCandidate **, size_t); + +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *); + +/* Détermine si deux candidats à l'unicité sont identiques. */ +static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *, const GSingletonCandidate *); + +/* Marque un candidat comme figé. */ +static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *); + +/* Indique si le candidat est figé. */ +static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *); + +/* Fournit l'empreinte d'un candidat à une centralisation. */ +static PyObject *py_singleton_candidate_hash(PyObject *, PyObject *); + +/* Fournit une liste de candidats embarqués par un candidat. */ +static PyObject *py_singleton_candidate_get_inner_instances(PyObject *, void *); + +/* Indique si le candidat est figé. */ +static PyObject *py_singleton_candidate_get_read_only(PyObject *, void *); + +/* Effectue une comparaison avec un objet 'SingletonCandidate'. */ +static PyObject *py_singleton_candidate_richcompare(PyObject *, PyObject *, int); + + + +/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ + + +/* Accompagne la création d'une instance dérivée en Python. */ +static PyObject *py_singleton_factory_new(PyTypeObject *, PyObject *, PyObject *); + +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_singleton_factory_init(PyObject *, PyObject *, PyObject *); + +/* Fournit l'instance unique correspondant à un objet. */ +static PyObject *py_singleton_factory_get_instance(PyObject *, PyObject *); + + + +/* ---------------------------------------------------------------------------------- */ +/* INTERFACE POUR CANDIDAT A UNE CENTRALISATION */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : iface = interface GLib à initialiser. * +* unused = adresse non utilisée ici. * +* * +* Description : Procède à l'initialisation de l'interface de candidature. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_singleton_candidate_interface_init(GSingletonCandidateIface *iface, gpointer *unused) +{ +#define SINGLETON_CANDIDATE_DOC \ + "The SingletonCandidate class is a required interface for objects" \ + " aiming at becoming singleton instances. All shared singletons are" \ + " registered within a pychrysalide.glibext.SingletonFactory object.\n" \ + "\n" \ + "The main implemantations come with types derived from" \ + " pychrysalide.analysis.DataType.\n" \ + "\n" \ + "A typical class declaration for a new implementation looks like:\n" \ + "\n" \ + " class NewImplem(GObject.Object, SingletonCandidate):\n" \ + " ...\n" \ + "\n" \ + "The following methods have to be defined for new implementations:\n" \ + "* pychrysalide.glibext.SingletonCandidate._list_inner_instances();\n" \ + "* pychrysalide.glibext.SingletonCandidate._update_inner_instances();\n"\ + "* pychrysalide.glibext.SingletonCandidate.__hash__();\n" \ + "* pychrysalide.glibext.SingletonCandidate.__eq__();\n" \ + "* pychrysalide.glibext.SingletonCandidate._set_read_only();\n" \ + "* pychrysalide.glibext.SingletonCandidate._is_read_only().\n" + + iface->update_inner = py_singleton_candidate_update_inner_instances_wrapper; + iface->list_inner = py_singleton_candidate_list_inner_instances_wrapper; + + iface->hash = py_singleton_candidate___hash__wrapper; + iface->is_equal = py_singleton_candidate___eq__wrapper; + + iface->set_ro = py_singleton_candidate_set_ro_wrapper; + iface->is_ro = py_singleton_candidate_is_ro_wrapper; + +} + + +/****************************************************************************** +* * +* Paramètres : candidate = objet dont l'instance se veut unique. * +* count = quantité d'instances à l'unicité internes. * +* * +* Description : Fournit une liste de candidats embarqués par un candidat. * +* * +* Retour : Liste de candidats internes ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GSingletonCandidate **py_singleton_candidate_list_inner_instances_wrapper(const GSingletonCandidate *candidate, size_t *count) +{ + GSingletonCandidate **result; /* Instances à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyinstances; /* Liste en version Python */ + int ret; /* Bilan d'un appel */ + Py_ssize_t size; /* Taille de la liste */ + Py_ssize_t i; /* Boucle de parcours #1 */ + PyObject *pyinstance; /* Instance interne */ + Py_ssize_t k; /* Boucle de parcours #2 */ + +#define SINGLETON_CANDIDATE_LIST_INNER_INSTANCES_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _list_inner_instances, "$self, /", \ + METH_NOARGS, \ + "Provide an internal access to the list of optional internal singleton" \ + " candidate instances.\n" \ + "\n" \ + "The result has to be a tuple containing zero or more" \ + " pychrysalide.glibext.SingletonCandidate instances." \ +) + + result = NULL; + *count = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(candidate)); + + if (has_python_method(pyobj, "_list_inner_instances")) + { + pyinstances = run_python_method(pyobj, "_list_inner_instances", NULL); + + if (pyinstances != NULL) + { + ret = PyTuple_Check(pyinstances); + if (!ret) + { + PyErr_SetString(PyExc_TypeError, "the _inner_instances attribute must be a tuple"); + goto done; + } + + size = PyTuple_GET_SIZE(pyinstances); + + result = calloc(size, sizeof(GSingletonCandidate *)); + + for (i = 0; i < size; i++) + { + pyinstance = PyTuple_GET_ITEM(pyinstances, i); + + ret = PyObject_IsInstance(pyinstance, (PyObject *)get_python_singleton_candidate_type()); + if (ret != 1) + { + PyErr_SetString(PyExc_TypeError, "the _inner_instances attribute must only contain pychrysalide.glibext.SingletonCandidate instances"); + + for (k = 0; k < i; k++) + g_object_unref(G_OBJECT(result[k])); + + free(result); + result = NULL; + + goto done; + + } + + result[i] = G_SINGLETON_CANDIDATE(pygobject_get(pyinstance)); + assert(result[i] != NULL); + + g_object_ref(G_OBJECT(result[i])); + + } + + *count = size; + + done: + + Py_DECREF(pyinstances); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : candidate = objet dont l'instance se veut unique. * +* instances = liste de candidats internes devenus singletons. * +* count = quantité d'instances à l'unicité internes. * +* * +* Description : Met à jour une liste de candidats embarqués par un candidat. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_singleton_candidate_update_inner_instances_wrapper(GSingletonCandidate *candidate, GSingletonCandidate **instances, size_t count) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyinstances; /* Liste d'instances converties*/ + size_t i; /* Boucle de parcours */ + PyObject *pyret; /* Bilan de consultation */ + +#define SINGLETON_CANDIDATE_UPDATE_INNER_INSTANCES_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _update_inner_instances, "$self, instances, /", \ + METH_VARARGS, \ + "Update the list of internal singleton candidate instances.\n" \ + "\n" \ + "The provided *instances* are a tuple of pychrysalide.glibext.SingletonCandidate" \ + " objets promoted as singletons." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(candidate)); + + if (has_python_method(pyobj, "_update_inner_instances")) + { + args = PyTuple_New(1); + + pyinstances = PyTuple_New(count); + PyTuple_SetItem(args, 0, pyinstances); + + for (i = 0; i < count; i++) + PyTuple_SetItem(pyinstances, i, pygobject_new(G_OBJECT(instances[i]))); + + pyret = run_python_method(pyobj, "_update_inner_instances", args); + + Py_XDECREF(pyret); + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : candidate = objet dont l'instance se veut unique. * +* * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * +* * +* Retour : Empreinte de l'élément représenté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static guint py_singleton_candidate___hash__wrapper(const GSingletonCandidate *candidate) +{ + guint result; /* Empreinte à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + +#define SINGLETON_CANDIDATE_HASH_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + __hash__, "$self, /", \ + METH_NOARGS, \ + "Abstract method used to produce a hash of the object.\n" \ + "\n" \ + "The result must be an integer value up to 64 bits." \ + "\n" \ + "Inner instances which are listed through the" \ + " pychrysalide.glibext.SingletonCandidate._list_inner_instances()" \ + " method do not need to get processed here as they are handled" \ + " automatically by the interface core." \ +) + + result = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(candidate)); + + if (has_python_method(pyobj, "__hash__")) + { + pyret = run_python_method(pyobj, "__hash__", NULL); + + if (pyret != NULL) + { + if (PyLong_Check(pyret)) + result = PyLong_AsUnsignedLongMask(pyret); + + Py_DECREF(pyret); + + } + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : candidate = objet dont l'instance se veut unique. * +* other = second élément à analyser. * +* * +* Description : Détermine si deux candidats à l'unicité sont identiques. * +* * +* Retour : Bilan de la comparaison. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static gboolean py_singleton_candidate___eq__wrapper(const GSingletonCandidate *candidate, const GSingletonCandidate *other) +{ + guint result; /* Empreinte à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *args; /* Arguments pour l'appel */ + PyObject *pyret; /* Bilan de consultation */ + +#define SINGLETON_CANDIDATE_EQ_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + __eq__, "$self, other, /", \ + METH_NOARGS, \ + "Abstract method used to provide the *__eq__* method for" \ + " rich comparison.\n" \ + "\n" \ + "The expected result is a boolean value." \ +) + + result = 0; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(candidate)); + + if (has_python_method(pyobj, "__eq__")) + { + args = PyTuple_New(1); + PyTuple_SetItem(args, 0, pygobject_new(G_OBJECT(other))); + + pyret = run_python_method(pyobj, "__eq__", args); + + if (pyret != NULL) + { + if (PyLong_Check(pyret)) + result = PyLong_AsUnsignedLong(pyret); + + Py_DECREF(pyret); + + } + + Py_DECREF(args); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : candidate = objet dont l'instance se veut unique. * +* * +* Description : Marque un candidat comme figé. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void py_singleton_candidate_set_ro_wrapper(GSingletonCandidate *candidate) +{ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + +#define SINGLETON_CANDIDATE_SET_RO_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _set_read_only, "$self, /", \ + METH_NOARGS, \ + "Abstract method used to mark the content of a singleton" \ + " candidate as read-only.\n" \ + "\n" \ + "The read-only state is mandatory once the candidate is" \ + " registered inside a pychrysalide.glibext.SingletonFactory"\ + " instance as official singleton." \ +) + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(candidate)); + + if (has_python_method(pyobj, "_set_read_only")) + { + pyret = run_python_method(pyobj, "_set_read_only", NULL); + + Py_XDECREF(pyret); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + +} + + +/****************************************************************************** +* * +* Paramètres : candidate = objet dont l'instance se veut unique. * +* * +* Description : Indique si le candidat est figé. * +* * +* Retour : true si le contenu du candidat ne peut plus être modifié. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_singleton_candidate_is_ro_wrapper(const GSingletonCandidate *candidate) +{ + bool result; /* Etat à retourner */ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan de consultation */ + +#define SINGLETON_CANDIDATE_IS_RO_WRAPPER PYTHON_WRAPPER_DEF \ +( \ + _is_read_only, "$self, /", \ + METH_NOARGS, \ + "Abstract method used to retrieve the status of the data" \ + " contained by a singleton candidate.\n" \ + "\n" \ + "The retured value is *True* if the candidate is" \ + " registered inside a pychrysalide.glibext.SingletonFactory"\ + " instance as official singleton, *False* otherwise." \ +) + + result = false; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(candidate)); + + if (has_python_method(pyobj, "_is_read_only")) + { + pyret = run_python_method(pyobj, "_is_read_only", NULL); + + result = (pyret == Py_True); + + Py_XDECREF(pyret); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet dont l'instance se veut unique. * +* args = adresse non utilisée ici. * +* * +* Description : Fournit l'empreinte d'un candidat à une centralisation. * +* * +* Retour : Empreinte de l'élément représenté. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_singleton_candidate_hash(PyObject *self, PyObject *args) +{ + PyObject *result; /* Emplacement à retourner */ + GSingletonCandidate *candidate; /* Mécanismes natifs */ + guint hash; /* Valeur d'empreitne */ + +#define SINGLETON_CANDIDATE_HASH_METHOD PYTHON_METHOD_DEF \ +( \ + hash, "$self", \ + METH_NOARGS, py_singleton_candidate, \ + "Compute the hash value of the singleton candidate.\n" \ + "\n" \ + "The method relies on the interface core to include in the" \ + " process the optional embedded instances which may become" \ + " singletons.\n" \ + "\n" \ + "The result is an integer value.\n" \ + "\n" \ + "Even if the Python *hash()* method, relying on the" \ + " pychrysalide.glibext.SingletonCandidate.__hash__()" \ + " implementation, provides values up to 64 bits, the final" \ + " hashes processed by the native GLib hash methods are" \ + " limited to 32 bits values." \ +) + + candidate = G_SINGLETON_CANDIDATE(pygobject_get(self)); + + hash = g_singleton_candidate_hash(candidate); + + result = PyLong_FromUnsignedLong(hash); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit une liste de candidats embarqués par un candidat. * +* * +* Retour : Liste de candidats internes, vide si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_singleton_candidate_get_inner_instances(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GSingletonCandidate *candidate; /* Mécanismes natifs */ + size_t count; /* Quantité d'objets internes */ + GSingletonCandidate **instances; /* Liste des embarqués */ + size_t i; /* Boucle de parcours */ + +#define SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + inner_instances, py_singleton_candidate, \ + "List of optional internal singleton candidate instances.\n" \ + "\n" \ + "The result has to be a tuple containing zero or more" \ + " pychrysalide.glibext.SingletonCandidate instances." \ +) + + candidate = G_SINGLETON_CANDIDATE(pygobject_get(self)); + + instances = g_singleton_candidate_list_inner_instances(candidate, &count); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { + PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(instances[i]))); + g_object_unref(G_OBJECT(instances[i])); + } + + if (instances != NULL) + free(instances); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique si le candidat est figé. * +* * +* Retour : true si le contenu du candidat ne peut plus être modifié. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_singleton_candidate_get_read_only(PyObject *self, void *closure) +{ + PyObject *result; /* Valeur à retourner */ + GSingletonCandidate *candidate; /* Mécanismes natifs */ + bool status; /* Etat de l'élément consulté */ + +#define SINGLETON_CANDIDATE_READ_ONLY_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + read_only, py_singleton_candidate, \ + "State of the singleton candidate content.\n" \ + "\n" \ + "The result is a boolean: *True* if the object is registered" \ + " as singleton, *False* otherwise.\n" \ + "\n" \ + "Once a singleton, the object must not change its content as" \ + " it is a shared instance." \ +) + + candidate = G_SINGLETON_CANDIDATE(pygobject_get(self)); + + status = g_singleton_candidate_is_read_only(candidate); + + result = status ? Py_True : Py_False; + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : a = premier object Python à consulter. * +* b = second object Python à consulter. * +* op = type de comparaison menée. * +* * +* Description : Effectue une comparaison avec un objet 'SingletonCandidate'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_singleton_candidate_richcompare(PyObject *a, PyObject *b, int op) +{ + PyObject *result; /* Bilan à retourner */ + int ret; /* Bilan de lecture des args. */ + GSingletonCandidate *cand_a; /* Premier élément à traiter */ + GSingletonCandidate *cand_b; /* Second élément à traiter */ + gboolean status; /* Résultat d'une comparaison */ + + if (op != Py_EQ) + { + result = Py_NotImplemented; + goto cmp_done; + } + + ret = PyObject_IsInstance(b, (PyObject *)get_python_singleton_candidate_type()); + if (!ret) + { + result = Py_NotImplemented; + goto cmp_done; + } + + cand_a = G_SINGLETON_CANDIDATE(pygobject_get(a)); + cand_b = G_SINGLETON_CANDIDATE(pygobject_get(b)); + + status = g_singleton_candidate_is_equal(cand_a, cand_b); + + result = (status ? Py_True : Py_False); + + cmp_done: + + Py_INCREF(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_singleton_candidate_type(void) +{ + static PyMethodDef py_singleton_candidate_methods[] = { + SINGLETON_CANDIDATE_LIST_INNER_INSTANCES_WRAPPER, + SINGLETON_CANDIDATE_UPDATE_INNER_INSTANCES_WRAPPER, + SINGLETON_CANDIDATE_HASH_WRAPPER, + SINGLETON_CANDIDATE_EQ_WRAPPER, + SINGLETON_CANDIDATE_SET_RO_WRAPPER, + SINGLETON_CANDIDATE_IS_RO_WRAPPER, + SINGLETON_CANDIDATE_HASH_METHOD, + { NULL } + }; + + static PyGetSetDef py_singleton_candidate_getseters[] = { + SINGLETON_CANDIDATE_INNER_INSTANCES_ATTRIB, + SINGLETON_CANDIDATE_READ_ONLY_ATTRIB, + { NULL } + }; + + static PyTypeObject py_singleton_candidate_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.glibext.SingletonCandidate", + .tp_basicsize = sizeof(PyObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SINGLETON_CANDIDATE_DOC, + + .tp_richcompare = py_singleton_candidate_richcompare, + + .tp_methods = py_singleton_candidate_methods, + .tp_getset = py_singleton_candidate_getseters + + }; + + return &py_singleton_candidate_type; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Prend en charge l'objet 'pychrysalide....SingletonCandidate'.* +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_singleton_candidate_is_registered(void) +{ + PyTypeObject *type; /* Type Python 'BinContent' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + static GInterfaceInfo info = { /* Paramètres d'inscription */ + + .interface_init = (GInterfaceInitFunc)py_singleton_candidate_interface_init, + .interface_finalize = NULL, + .interface_data = NULL, + + }; + + type = get_python_singleton_candidate_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.glibext"); + + dict = PyModule_GetDict(module); + + if (!register_interface_for_pygobject(dict, G_TYPE_SINGLETON_CANDIDATE, type, &info)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en candidat à une centralisation. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_singleton_candidate(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_singleton_candidate_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to singleton candidate"); + break; + + case 1: + *((GSingletonCandidate **)dst) = G_SINGLETON_CANDIDATE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* COLLECTION D'INSTANCES UNIQUES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : type = type du nouvel objet à mettre en place. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition. * +* * +* Description : Accompagne la création d'une instance dérivée en Python. * +* * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_singleton_factory_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type de base à dériver */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + base = get_python_singleton_factory_type(); + + if (type == base) + goto simple_way; + + /* Mise en place d'un type dédié */ + + first_time = (g_type_from_name(type->tp_name) == 0); + + gtype = build_dynamic_type(G_TYPE_SINGLETON_FACTORY, type->tp_name, NULL, NULL, NULL); + + if (first_time) + { + status = register_class_for_dynamic_pygobject(gtype, type); + + if (!status) + { + result = NULL; + goto exit; + } + + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + simple_way: + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet à initialiser (théoriquement). * +* args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * +* * +* Description : Initialise une instance sur la base du dérivé de GObject. * +* * +* Retour : 0. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static int py_singleton_factory_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + int ret; /* Bilan de lecture des args. */ + +#define SINGLETON_FACTORY_DOC \ + "The SingletonFactory class reduces the memory footprint by compacting" \ + " the quantity of running instances of a given GLib type.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " SingletonFactory()" \ + "\n" \ + "The first processed instance defines the type handled by the factory." + + /* Récupération des paramètres */ + + ret = PyArg_ParseTuple(args, ""); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = gestionnaire d'instances uniques à consulter. * +* args = arguments fournis à l'appel. * +* * +* Description : Fournit l'instance unique correspondant à un objet. * +* * +* Retour : Instance unique à utiliser. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_singleton_factory_get_instance(PyObject *self, PyObject *args) +{ + PyObject *result; /* Emplacement à retourner */ + GSingletonCandidate *candidate; /* Candidat à traiter */ + int ret; /* Bilan de lecture des args. */ + GSingletonFactory *factory; /* Gestionnaire à manipuler */ + GSingletonCandidate *instance; /* Instance unique à retourner */ + +#define SINGLETON_FACTORY_GET_INSTANCE_METHOD PYTHON_METHOD_DEF \ +( \ + get_instance, "$self, candidate, /", \ + METH_VARARGS, py_singleton_factory, \ + "Provide the unique instance for a given singleton *candidate*.\n" \ + "\n" \ + "The *candidate* object and the result of the function belong to" \ + " the same type: pychrysalide.glibext.SingletonCandidate." \ +) + + ret = PyArg_ParseTuple(args, "O&", convert_to_singleton_candidate, &candidate); + if (!ret) return NULL; + + factory = G_SINGLETON_FACTORY(pygobject_get(self)); + + instance = g_singleton_factory_get_instance(factory, candidate); + + result = pygobject_new(G_OBJECT(instance)); + + g_object_unref(G_OBJECT(instance)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Fournit un accès à une définition de type à diffuser. * +* * +* Retour : Définition d'objet pour Python. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyTypeObject *get_python_singleton_factory_type(void) +{ + static PyMethodDef py_singleton_factory_methods[] = { + SINGLETON_FACTORY_GET_INSTANCE_METHOD, + { NULL } + }; + + static PyGetSetDef py_singleton_factory_getseters[] = { + { NULL } + }; + + static PyTypeObject py_singleton_factory_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.glibext.SingletonFactory", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + + .tp_doc = SINGLETON_FACTORY_DOC, + + .tp_methods = py_singleton_factory_methods, + .tp_getset = py_singleton_factory_getseters, + + .tp_init = py_singleton_factory_init, + .tp_new = py_singleton_factory_new + + }; + + return &py_singleton_factory_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide....SingletonFactory'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool ensure_python_singleton_factory_is_registered(void) +{ + PyTypeObject *type; /* Type 'SingletonFactory' */ + PyObject *module; /* Module à recompléter */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_singleton_factory_type(); + + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.glibext"); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_SINGLETON_FACTORY, type)) + return false; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en compacteur d'instances. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_singleton_factory(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_singleton_factory_type()); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to singleton factory"); + break; + + case 1: + *((GSingletonFactory **)dst) = G_SINGLETON_FACTORY(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/pychrysalide/glibext/singleton.h b/plugins/pychrysalide/glibext/singleton.h new file mode 100644 index 0000000..6479219 --- /dev/null +++ b/plugins/pychrysalide/glibext/singleton.h @@ -0,0 +1,62 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * singleton.h - prototypes pour l'équivalent Python du fichier "glibext/singleton.h" + * + * Copyright (C) 2021 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_PYCHRYSALIDE_GLIBEXT_SINGLETON_H +#define _PLUGINS_PYCHRYSALIDE_GLIBEXT_SINGLETON_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* ------------------ INTERFACE POUR CANDIDAT A UNE CENTRALISATION ------------------ */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_singleton_candidate_type(void); + +/* Prend en charge l'objet 'pychrysalide.glibext.SingletonCandidate'. */ +bool ensure_python_singleton_candidate_is_registered(void); + +/* Tente de convertir en candidat à une centralisation. */ +int convert_to_singleton_candidate(PyObject *, void *); + + + +/* ------------------------- COLLECTION D'INSTANCES UNIQUES ------------------------- */ + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_singleton_factory_type(void); + +/* Prend en charge l'objet 'pychrysalide.glibext.SingletonFactory'. */ +bool ensure_python_singleton_factory_is_registered(void); + +/* Tente de convertir en compacteur d'instances. */ +int convert_to_singleton_factory(PyObject *, void *); + + + +#endif /* _PLUGINS_PYCHRYSALIDE_GLIBEXT_SINGLETON_H */ diff --git a/plugins/pychrysalide/gtkext/Makefile.am b/plugins/pychrysalide/gtkext/Makefile.am index 77cce65..2e1260f 100644 --- a/plugins/pychrysalide/gtkext/Makefile.am +++ b/plugins/pychrysalide/gtkext/Makefile.am @@ -1,19 +1,20 @@ noinst_LTLIBRARIES = libpychrysagtkext.la -libpychrysagtkext_la_SOURCES = \ - blockdisplay.h blockdisplay.c \ - bufferdisplay.h bufferdisplay.c \ - displaypanel.h displaypanel.c \ - dockable.h dockable.c \ - easygtk.h easygtk.c \ - module.h module.c \ +libpychrysagtkext_la_SOURCES = \ + blockdisplay.h blockdisplay.c \ + bufferdisplay.h bufferdisplay.c \ + displaypanel.h displaypanel.c \ + dockable.h dockable.c \ + easygtk.h easygtk.c \ + module.h module.c \ named.h named.c -libpychrysagtkext_la_LIBADD = \ +libpychrysagtkext_la_LIBADD = \ graph/libpychrysagtkextgraph.la -libpychrysagtkext_la_LDFLAGS = +libpychrysagtkext_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -21,10 +22,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysagtkext_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - - SUBDIRS = graph diff --git a/plugins/pychrysalide/gtkext/blockdisplay.c b/plugins/pychrysalide/gtkext/blockdisplay.c index 6741553..b4b8515 100644 --- a/plugins/pychrysalide/gtkext/blockdisplay.c +++ b/plugins/pychrysalide/gtkext/blockdisplay.c @@ -115,7 +115,7 @@ bool ensure_python_block_display_is_registered(void) if (!ensure_python_buffer_display_is_registered()) return false; - if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, type, get_python_buffer_display_type())) + if (!register_class_for_pygobject(dict, GTK_TYPE_BLOCK_DISPLAY, type)) return false; } diff --git a/plugins/pychrysalide/gtkext/bufferdisplay.c b/plugins/pychrysalide/gtkext/bufferdisplay.c index 310e60a..4babcc8 100644 --- a/plugins/pychrysalide/gtkext/bufferdisplay.c +++ b/plugins/pychrysalide/gtkext/bufferdisplay.c @@ -115,7 +115,7 @@ bool ensure_python_buffer_display_is_registered(void) if (!ensure_python_display_panel_is_registered()) return false; - if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, type, get_python_display_panel_type())) + if (!register_class_for_pygobject(dict, GTK_TYPE_BUFFER_DISPLAY, type)) return false; } diff --git a/plugins/pychrysalide/gtkext/displaypanel.c b/plugins/pychrysalide/gtkext/displaypanel.c index dc7b8e5..a871af9 100644 --- a/plugins/pychrysalide/gtkext/displaypanel.c +++ b/plugins/pychrysalide/gtkext/displaypanel.c @@ -98,42 +98,23 @@ PyTypeObject *get_python_display_panel_type(void) bool ensure_python_display_panel_is_registered(void) { - bool result; /* Bilan à retourner */ PyTypeObject *type; /* Type Python 'DisplayPanel' */ - PyObject *parent_mod; /* Module Python Fixed */ - PyObject *fixed; /* Module "GtkFixed" */ PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ - result = false; - type = get_python_display_panel_type(); if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) { module = get_access_to_python_module("pychrysalide.gtkext"); - parent_mod = PyImport_ImportModule("gi.repository.Gtk"); - - if (parent_mod == NULL) - goto rpdp_exit; - - fixed = PyObject_GetAttrString(parent_mod, "Fixed"); - - Py_DECREF(parent_mod); - dict = PyModule_GetDict(module); - result = register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL, type, (PyTypeObject *)fixed); - Py_DECREF(fixed); + if (!register_class_for_pygobject(dict, GTK_TYPE_DISPLAY_PANEL, type)) + return false; } - else - result = true; - - rpdp_exit: - - return result; + return true; } diff --git a/plugins/pychrysalide/gtkext/graph/Makefile.am b/plugins/pychrysalide/gtkext/graph/Makefile.am index 7e9b5e5..25e3088 100644 --- a/plugins/pychrysalide/gtkext/graph/Makefile.am +++ b/plugins/pychrysalide/gtkext/graph/Makefile.am @@ -1,21 +1,16 @@ noinst_LTLIBRARIES = libpychrysagtkextgraph.la -libpychrysagtkextgraph_la_SOURCES = \ - constants.h constants.c \ - cluster.h cluster.c \ - edge.h edge.c \ +libpychrysagtkextgraph_la_SOURCES = \ + constants.h constants.c \ + cluster.h cluster.c \ + edge.h edge.c \ module.h module.c -libpychrysagtkextgraph_la_LDFLAGS = +libpychrysagtkextgraph_la_CFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysagtkextgraph_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/gtkext/graph/cluster.c b/plugins/pychrysalide/gtkext/graph/cluster.c index fc73276..11cb8fa 100644 --- a/plugins/pychrysalide/gtkext/graph/cluster.c +++ b/plugins/pychrysalide/gtkext/graph/cluster.c @@ -656,7 +656,7 @@ bool ensure_python_graph_cluster_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_CLUSTER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_CLUSTER, type)) return false; } diff --git a/plugins/pychrysalide/gtkext/graph/edge.c b/plugins/pychrysalide/gtkext/graph/edge.c index ce20ce9..d016e30 100644 --- a/plugins/pychrysalide/gtkext/graph/edge.c +++ b/plugins/pychrysalide/gtkext/graph/edge.c @@ -267,7 +267,7 @@ bool ensure_python_graph_edge_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_EDGE, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_GRAPH_EDGE, type)) return false; if (!define_graph_edge_constants(type)) diff --git a/plugins/pychrysalide/gtkext/named.c b/plugins/pychrysalide/gtkext/named.c index e272097..ee963de 100644 --- a/plugins/pychrysalide/gtkext/named.c +++ b/plugins/pychrysalide/gtkext/named.c @@ -99,7 +99,7 @@ static PyObject *py_built_named_widget_new(PyTypeObject *type, PyObject *args, P if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -278,12 +278,7 @@ PyTypeObject *get_python_built_named_widget_type(void) }; - static PyTypeObject *result = NULL; - - if (result == NULL) - result = define_python_dynamic_type(&py_built_named_widget_type); - - return result; + return &py_built_named_widget_type; } @@ -317,7 +312,7 @@ bool ensure_python_built_named_widget_is_registered(void) if (!ensure_python_named_widget_is_registered()) return false; - if (!register_class_for_pygobject(dict, GTK_TYPE_BUILT_NAMED_WIDGET, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, GTK_TYPE_BUILT_NAMED_WIDGET, type)) return false; } diff --git a/plugins/pychrysalide/gui/Makefile.am b/plugins/pychrysalide/gui/Makefile.am index 360f7ff..de2e888 100644 --- a/plugins/pychrysalide/gui/Makefile.am +++ b/plugins/pychrysalide/gui/Makefile.am @@ -1,18 +1,19 @@ noinst_LTLIBRARIES = libpychrysagui.la -libpychrysagui_la_SOURCES = \ - constants.h constants.c \ - item.h item.c \ - menubar.h menubar.c \ - module.h module.c \ +libpychrysagui_la_SOURCES = \ + constants.h constants.c \ + item.h item.c \ + menubar.h menubar.c \ + module.h module.c \ panel.h panel.c -libpychrysagui_la_LIBADD = \ - core/libpychrysaguicore.la \ +libpychrysagui_la_LIBADD = \ + core/libpychrysaguicore.la \ panels/libpychrysaguipanels.la -libpychrysagui_la_LDFLAGS = +libpychrysagui_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) @@ -20,9 +21,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysagui_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = core panels diff --git a/plugins/pychrysalide/gui/core/Makefile.am b/plugins/pychrysalide/gui/core/Makefile.am index 02f3596..8f49176 100644 --- a/plugins/pychrysalide/gui/core/Makefile.am +++ b/plugins/pychrysalide/gui/core/Makefile.am @@ -1,21 +1,16 @@ noinst_LTLIBRARIES = libpychrysaguicore.la -libpychrysaguicore_la_SOURCES = \ - global.h global.c \ - items.h items.c \ - module.h module.c \ +libpychrysaguicore_la_SOURCES = \ + global.h global.c \ + items.h items.c \ + module.h module.c \ panels.h panels.c -libpychrysaguicore_la_LDFLAGS = +libpychrysaguicore_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaguicore_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/gui/item.c b/plugins/pychrysalide/gui/item.c index 2046587..0c604b5 100644 --- a/plugins/pychrysalide/gui/item.c +++ b/plugins/pychrysalide/gui/item.c @@ -291,19 +291,16 @@ static GtkWidget *py_editor_item_get_widget_wrapper(const GEditorItem *item) static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedContent *old, GLoadedContent *new) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *pyold; /* Conversion ou None */ PyObject *pynew; /* Conversion ou None */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_change_content")) { @@ -334,8 +331,7 @@ static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedCont } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -356,19 +352,16 @@ static void py_editor_item_change_content_wrapper(GEditorItem *item, GLoadedCont static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel *old, GLoadedPanel *new) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *pyold; /* Conversion ou None */ PyObject *pynew; /* Conversion ou None */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_change_view")) { @@ -399,8 +392,7 @@ static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel * } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -420,17 +412,14 @@ static void py_editor_item_change_view_wrapper(GEditorItem *item, GLoadedPanel * static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel *panel) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_update_view")) { @@ -444,8 +433,7 @@ static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel * } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -466,17 +454,14 @@ static void py_editor_item_update_view_wrapper(GEditorItem *item, GLoadedPanel * static void py_editor_item_track_cursor_wrapper(GEditorItem *item, GLoadedPanel *panel, const GLineCursor *cursor) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_track_cursor")) { @@ -491,8 +476,7 @@ static void py_editor_item_track_cursor_wrapper(GEditorItem *item, GLoadedPanel } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -513,17 +497,14 @@ static void py_editor_item_track_cursor_wrapper(GEditorItem *item, GLoadedPanel static void py_editor_item_focus_cursor_wrapper(GEditorItem *item, GLoadedContent *content, const GLineCursor *cursor) { + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ PyObject *pyobj; /* Objet Python concerné */ - PyThreadState *tstate; /* Contexte d'environnement */ PyObject *args; /* Arguments pour l'appel */ PyObject *pyret; /* Retour de Python */ - pyobj = pygobject_new(G_OBJECT(item)); - - tstate = get_pychrysalide_main_tstate(); + gstate = PyGILState_Ensure(); - if (tstate != NULL) - PyEval_RestoreThread(tstate); + pyobj = pygobject_new(G_OBJECT(item)); if (has_python_method(pyobj, "_focus_cursor")) { @@ -538,8 +519,7 @@ static void py_editor_item_focus_cursor_wrapper(GEditorItem *item, GLoadedConten } - if (tstate != NULL) - PyEval_SaveThread(); + PyGILState_Release(gstate); } @@ -711,7 +691,7 @@ bool ensure_python_editor_item_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_EDITOR_ITEM, type)) return false; } diff --git a/plugins/pychrysalide/gui/menubar.c b/plugins/pychrysalide/gui/menubar.c index 5c6270e..29b76ac 100644 --- a/plugins/pychrysalide/gui/menubar.c +++ b/plugins/pychrysalide/gui/menubar.c @@ -160,7 +160,10 @@ bool ensure_python_menu_bar_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_MENU_BAR, type, get_python_editor_item_type())) + if (!ensure_python_editor_item_is_registered()) + return false; + + if (!register_class_for_pygobject(dict, G_TYPE_MENU_BAR, type)) return false; } diff --git a/plugins/pychrysalide/gui/panel.c b/plugins/pychrysalide/gui/panel.c index 2afb2a1..949243c 100644 --- a/plugins/pychrysalide/gui/panel.c +++ b/plugins/pychrysalide/gui/panel.c @@ -164,7 +164,7 @@ static PyObject *py_panel_item_new(PyTypeObject *type, PyObject *args, PyObject if (first_time) { - status = register_class_for_dynamic_pygobject(gtype, type, base); + status = register_class_for_dynamic_pygobject(gtype, type); if (!status) { @@ -1188,8 +1188,7 @@ bool ensure_python_panel_item_is_registered(void) if (!ensure_python_dockable_is_registered()) return false; - if (!_register_class_for_pygobject(dict, G_TYPE_PANEL_ITEM, type, - get_python_editor_item_type(), get_python_dockable_type(), NULL)) + if (!register_class_for_pygobject(dict, G_TYPE_PANEL_ITEM, type)) return false; if (!define_panel_item_constants(type)) diff --git a/plugins/pychrysalide/gui/panels/Makefile.am b/plugins/pychrysalide/gui/panels/Makefile.am index 9585ec4..067c798 100644 --- a/plugins/pychrysalide/gui/panels/Makefile.am +++ b/plugins/pychrysalide/gui/panels/Makefile.am @@ -1,19 +1,14 @@ noinst_LTLIBRARIES = libpychrysaguipanels.la -libpychrysaguipanels_la_SOURCES = \ - module.h module.c \ +libpychrysaguipanels_la_SOURCES = \ + module.h module.c \ updating.h updating.c -libpychrysaguipanels_la_LDFLAGS = +libpychrysaguipanels_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaguipanels_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/pychrysalide/helpers.c b/plugins/pychrysalide/helpers.c index 92a5db9..c2b1868 100644 --- a/plugins/pychrysalide/helpers.c +++ b/plugins/pychrysalide/helpers.c @@ -32,11 +32,14 @@ #include <stdlib.h> #include <string.h> #include <strings.h> -#include <gtk/gtk.h> +#ifdef INCLUDE_GTK_SUPPORT +# include <gtk/gtk.h> +#endif #include <i18n.h> #include <common/extstr.h> +#include <plugins/dt.h> #include "access.h" @@ -233,6 +236,8 @@ PyObject *run_python_method(PyObject *module, const char *method, PyObject *args PyObject *traceback; /* Pile d'appels de l'exception*/ PyObject *refmsg; /* Message de référence */ + assert(PyGILState_Check() == 1); + /* Exécution */ result = NULL; @@ -505,6 +510,131 @@ bool register_python_module_object(PyObject *module, PyTypeObject *type) /****************************************************************************** * * +* Paramètres : type = type du nouvel objet à mettre en place. * +* gbase = type de base natif. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition.* +* * +* Description : Accompagne la création d'une instance dérivée en Python. * +* * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *type, GType gbase, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type parent version Python */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + base = pygobject_lookup_class(gbase); + + if (type == base) + goto simple_way; + + /* Mise en place d'un type dédié */ + + first_time = (g_type_from_name(type->tp_name) == 0); + + gtype = build_dynamic_type(gbase, type->tp_name, NULL, NULL, NULL); + + if (first_time) + { + status = register_class_for_dynamic_pygobject(gtype, type); + + if (!status) + { + result = NULL; + goto exit; + } + + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + simple_way: + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : type = type du nouvel objet à mettre en place. * +* gbase = type de base natif. * +* cinit = procédure d'initialisation de la classe associée. * +* args = éventuelle liste d'arguments. * +* kwds = éventuel dictionnaire de valeurs mises à disposition.* +* * +* Description : Accompagne la création d'une instance dérivée en Python. * +* * +* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *python_abstract_constructor_with_dynamic_gtype(PyTypeObject *type, GType gbase, GClassInitFunc cinit, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Objet à retourner */ + PyTypeObject *base; /* Type parent version Python */ + bool first_time; /* Evite les multiples passages*/ + GType gtype; /* Nouveau type de processeur */ + bool status; /* Bilan d'un enregistrement */ + + /* Validations diverses */ + + base = pygobject_lookup_class(gbase); + + if (type == base) + { + result = NULL; + PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); + goto exit; + } + + /* Mise en place d'un type dédié */ + + first_time = (g_type_from_name(type->tp_name) == 0); + + gtype = build_dynamic_type(gbase, type->tp_name, cinit, NULL, NULL); + + if (first_time) + { + status = register_class_for_dynamic_pygobject(gtype, type); + + if (!status) + { + result = NULL; + goto exit; + } + + } + + /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ + + result = PyType_GenericNew(type, args, kwds); + + exit: + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : type = type du nouvel objet à mettre en place. * * args = éventuelle liste d'arguments. * * kwds = éventuel dictionnaire de valeurs mises à disposition. * @@ -659,7 +789,7 @@ PyObject *not_yet_implemented_getter(PyObject *self, void *closure) /****************************************************************************** * * -* Paramètres : spec = définition à mettre en place dynamiquement. * +* Paramètres : otype = définition à mettre en place dynamiquement. * * * * Description : Définit dans le tas de Python un nouveau type. * * * @@ -669,102 +799,63 @@ PyObject *not_yet_implemented_getter(PyObject *self, void *closure) * * ******************************************************************************/ -PyTypeObject *define_python_dynamic_type(const PyTypeObject *spec) +PyTypeObject *define_python_dynamic_type(const PyTypeObject *otype) { PyTypeObject *result; /* Définition créée à renvoyer */ - PyTypeObject *type; /* Type de tous les types */ - size_t size; /* Taille de la définition */ - char *s; /* Marqueur de début de chaîne */ - PyHeapTypeObject *hobj; /* Version réelle du type créé */ + PyType_Slot slots[10]; /* Emplacements pour infos */ + PyType_Spec spec; /* Définition du type */ + PyType_Slot *iter; /* Boucle de parcours */ + PyObject *bases; /* Bases de construction */ - /** - * Le cahier des charges est ici d'éviter les erreurs suivantes : - * - * TypeError: type 'XXX' is not dynamically allocated but its base type 'YYY' is dynamically allocated - * Fatal Python error: unexpected exception during garbage collection - * - * L'allocation dynamique est marquée par le fanion Py_TPFLAGS_HEAPTYPE. - * - * Une des rares fonctions qui appliquent ce fanion est PyType_FromSpecWithBases(), - * mais elle appelle ensuite PyType_Ready(), ce qui est incompatible avec des modifications - * utltérieures avant un appel à pygobject_register_class(). - * - * Le code suivant s'inspire fortement des méthodes originales de Python, - * dont les mécanismes employés par PyType_GenericAlloc(). - */ - - type = &PyType_Type; - size = _PyObject_SIZE(type); - - if (PyType_IS_GC(type)) - result = (PyTypeObject *)_PyObject_GC_Malloc(size); - else - result = (PyTypeObject *)PyObject_MALLOC(size); - - if (type->tp_flags & Py_TPFLAGS_HEAPTYPE) - Py_INCREF(type); - - /* Définitions sommaires */ - - memset(result, 0, sizeof(PyHeapTypeObject)); + bases = PyTuple_Pack(1, &PyType_Type); - memcpy(result, spec, sizeof(PyTypeObject)); - - result->tp_flags |= Py_TPFLAGS_HEAPTYPE; - - /* Définitions des noms */ - - /** - * Pour un type dynamique, les désignations ne s'appuient pas sur la partie réservée - * au type, mais sur les données suivantes (cf. type_name() et type_qualname()). - * - * Les deux fonctions désignées sont par ailleurs facilement accessibles : - * - * #0 0x0000555555689bf0 in type_qualname (...) at Objects/typeobject.c:393 - * #1 0x000055555568b3b4 in type_repr (...) at Objects/typeobject.c:855 - * #2 0x0000555555693574 in object_str (...) at Objects/typeobject.c:3511 - * #3 0x0000555555670d02 in PyObject_Str (...) at Objects/object.c:535 - * ... - * - * On s'inspire donc du contenu de PyType_FromSpecWithBases() pour éviter tout - * plantage du fait de données non initialisées. - */ - - hobj = (PyHeapTypeObject *)result; - - s = strrchr(spec->tp_name, '.'); - - if (s == NULL) - s = (char *)spec->tp_name; - else - s++; + spec.name = otype->tp_name; + spec.basicsize = otype->tp_basicsize; + spec.flags = otype->tp_flags; + spec.slots = slots; - hobj->ht_name = PyUnicode_FromString(s); - assert(hobj->ht_name != NULL); + iter = &slots[0]; - hobj->ht_qualname = hobj->ht_name; - Py_INCREF(hobj->ht_qualname); + if (otype->tp_doc != NULL) + { + iter->slot = Py_tp_doc; + iter->pfunc = (void *)otype->tp_doc; + iter++; + } - result->tp_as_async = &hobj->as_async; - result->tp_as_number = &hobj->as_number; - result->tp_as_sequence = &hobj->as_sequence; - result->tp_as_mapping = &hobj->as_mapping; - result->tp_as_buffer = &hobj->as_buffer; + if (otype->tp_methods != NULL) + { + iter->slot = Py_tp_methods; + iter->pfunc = otype->tp_methods; + iter++; + } - hobj->ht_cached_keys = _PyDict_NewKeysForClass(); + if (otype->tp_getset != NULL) + { + iter->slot = Py_tp_getset; + iter->pfunc = otype->tp_getset; + iter++; + } + if (otype->tp_init != NULL) + { + iter->slot = Py_tp_init; + iter->pfunc = otype->tp_init; + iter++; + } + if (otype->tp_new != NULL) + { + iter->slot = Py_tp_new; + iter->pfunc = otype->tp_new; + iter++; + } + iter->slot = 0; -#if 0 - if (type->tp_itemsize == 0) - (void)PyObject_INIT(result, type); - else - (void) PyObject_INIT_VAR((PyVarObject *)result, type, 0); + result = (PyTypeObject *)PyType_FromSpecWithBases(&spec, bases); - if (PyType_IS_GC(type)) - _PyObject_GC_TRACK(result); -#endif + Py_DECREF(bases); return result; @@ -800,7 +891,6 @@ static void define_auto_documentation(PyTypeObject *type) * Paramètres : dict = dictionnaire où conserver une référence au type créé.* * gtype = type dans sa version GLib. * * type = type dans sa version Python. * -* base = type de base de l'objet. * * * * Description : Enregistre correctement une surcouche de conversion GObject. * * * @@ -810,13 +900,11 @@ static void define_auto_documentation(PyTypeObject *type) * * ******************************************************************************/ -bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type, PyTypeObject *base, ...) +bool register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *type) { bool result; /* Bilan à retourner */ - Py_ssize_t size; /* Taille de liste actuelle */ - PyObject *static_bases; /* Base(s) de l'objet */ - va_list ap; /* Parcours des arguments */ - PyTypeObject *static_base; /* Base à rajouter à la liste */ + GType parent_type; /* Type parent version GObject */ + PyTypeObject *base; /* Type parent version Python */ assert(gtype != G_TYPE_INVALID); @@ -841,45 +929,17 @@ bool _register_class_for_pygobject(PyObject *dict, GType gtype, PyTypeObject *ty * Et quelqu'un doit se coller à la tâche. PyGObject ne fait rien, donc... */ + parent_type = g_type_parent(gtype); + + base = pygobject_lookup_class(parent_type); + if (type->tp_basicsize < base->tp_basicsize) { assert(type->tp_basicsize == 0); type->tp_basicsize = base->tp_basicsize; } - size = 1; - static_bases = PyTuple_New(size); - - Py_INCREF(base); - PyTuple_SetItem(static_bases, 0, (PyObject *)base); - - va_start(ap, base); - - while (1) - { - static_base = va_arg(ap, PyTypeObject *); - - if (static_base == NULL) break; - - _PyTuple_Resize(&static_bases, ++size); - - Py_INCREF(static_base); - PyTuple_SetItem(static_bases, size - 1, (PyObject *)static_base); - - } - - va_end(ap); - - /** - * les renseignements suivants ne semblent pas nécessaires... - */ - - /* - type->tp_weaklistoffset = offsetof(PyGObject, weakreflist); - type->tp_dictoffset = offsetof(PyGObject, inst_dict); - */ - - pygobject_register_class(dict, NULL, gtype, type, static_bases); + pygobject_register_class(dict, NULL, gtype, type, NULL); if (PyErr_Occurred() == NULL) result = true; @@ -956,10 +1016,8 @@ bool register_interface_for_pygobject(PyObject *dict, GType gtype, PyTypeObject /****************************************************************************** * * -* Paramètres : dict = dictionnaire où conserver une référence au type créé.* -* gtype = type dans sa version GLib. * +* Paramètres : gtype = type dans sa version GLib. * * type = type dans sa version Python. * -* base = type de base de l'objet. * * * * Description : Enregistre un type Python dérivant d'un type GLib dynamique. * * * @@ -969,7 +1027,7 @@ bool register_interface_for_pygobject(PyObject *dict, GType gtype, PyTypeObject * * ******************************************************************************/ -bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTypeObject *base) +bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type) { bool result; /* Bilan à retourner */ PyTypeObject *legacy_parent; /* Type parent d'origine */ @@ -1024,9 +1082,9 @@ bool register_class_for_dynamic_pygobject(GType gtype, PyTypeObject *type, PyTyp dict = PyModule_GetDict(module); - result = _register_class_for_pygobject(dict, gtype, type, &PyGObject_Type, base, NULL); + result = register_class_for_pygobject(dict, gtype, type); - Py_TYPE(type) = legacy_parent; + Py_SET_TYPE(type, legacy_parent); /** * Comme la mise en place dynamique de nouveau GType court-circuite les @@ -1189,6 +1247,9 @@ int convert_to_gobject(PyObject *arg, void *dst) } +#ifdef INCLUDE_GTK_SUPPORT + + /****************************************************************************** * * * Paramètres : arg = argument quelconque à tenter de convertir. * @@ -1299,6 +1360,9 @@ int convert_to_gtk_container(PyObject *arg, void *dst) } +#endif + + /****************************************************************************** * * * Paramètres : color = couleur dans sa définition native à copier. * @@ -1440,15 +1504,15 @@ int convert_to_gdk_rgba(PyObject *arg, void *dst) * * * Description : Officialise un groupe de constantes avec sémentique. * * * -* Retour : true en cas de succès de l'opération, false sinon. * +* Retour : Groupe de constantes mis en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ -bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, const char *name, PyObject *values, const char *doc) +PyObject *_attach_constants_group(const char *owner, PyObject *dict, bool flags, const char *name, PyObject *values, const char *doc) { - bool result; /* Bilan à retourner */ + PyObject *result; /* Instance à retourner */ PyObject *enum_mod; /* Module Python enum */ PyObject *class; /* Classe "Enum*" */ PyObject *str_obj; /* Conversion en Python */ @@ -1462,7 +1526,7 @@ bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, cons PyObject *features; /* Module à recompléter */ PyObject *features_dict; /* Dictionnaire à compléter */ - result = false; + result = NULL; /* Recherche de la classe Python */ @@ -1539,7 +1603,8 @@ bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, cons ret = PyDict_SetItemString(features_dict, name, new); if (ret != 0) goto register_1_error; - result = true; + result = new; + Py_INCREF(result); /* Sortie propre */ @@ -1570,6 +1635,99 @@ bool _attach_constants_group(const char *owner, PyObject *dict, bool flags, cons } +/****************************************************************************** +* * +* Paramètres : owner = désignation du propriétaire du dictionnaire visé. * +* dict = dictionnaire dont le contenu est à compléter. * +* flags = indique le type d'énumération ciblée. * +* name = désignation humaine du groupe à constituer. * +* values = noms et valeurs associées. * +* doc = documentation à associer au groupe. * +* gtype = énumération GLib à lier. * +* * +* Description : Officialise un groupe de constantes avec lien GLib. * +* * +* Retour : Groupe de constantes mis en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +PyObject *_attach_constants_group_with_pyg_enum(const char *owner, PyObject *dict, bool flags, const char *name, PyObject *values, const char *doc, GType gtype) +{ + PyObject *result; /* Instance à retourner */ + PyObject *values_set; /* Zone pour nouvelles valeurs */ + int ret; /* Bilan d'une insertion */ + PyObject *new; /* Nouvelle instance en place */ + PyObject *values_src; /* Source de nouvelles valeurs */ + PyObject *values_dest; /* Destination des valeurs */ + + static GQuark pygenum_class_key = 0; /* Clef d'accès au marquage */ + + result = NULL; + + /** + * Le seul intérêt d'un tel enregistrement en bonne et due forme est de + * permettre une impression, via str() ou repr(), de l'énumération + * transcrite en GLib via g_enum_register_static() et potentiellement + * convertie de façon brusque par _pygi_argument_to_object(), lors d'une + * émission de signal par exemple. + * + * La satisfaction de la fonction pyg_enum_from_gtype() est ainsi recherchée. + * Tous les éléments sont normalement mis en place à partir de la fonction + * pyg_enum_add(). + */ + + /* Préparation du réceptacle */ + + values_set = PyDict_New(); + + ret = PyDict_SetItemString(values, "__enum_values__", values_set); + + Py_DECREF(values_set); + + if (ret != 0) goto exit; + + /* Création */ + + new = _attach_constants_group(owner, dict, flags, name, values, doc); + if (new == NULL) goto exit; + + /* Actualisation des valeurs */ + + values_src = PyDict_GetItemString(((PyTypeObject *)new)->tp_dict, "_value2member_map_"); + if (values_src == NULL) goto exit_without_src; + + values_dest = PyDict_GetItemString(((PyTypeObject *)new)->tp_dict, "__enum_values__"); + if (values_dest == NULL) goto exit_without_dest; + + assert(values_dest == values_set); + + ret = PyDict_Merge(values_dest, values_src, true); + + if (ret == 0) + { + result = new; + Py_INCREF(result); + + if (pygenum_class_key == 0) + pygenum_class_key = g_quark_from_static_string("PyGEnum::class"); + + g_type_set_qdata(gtype, pygenum_class_key, result); + + } + + exit_without_dest: + exit_without_src: + + Py_DECREF(new); + + exit: + + return result; + +} + /****************************************************************************** * * diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index 931be95..57cf96d 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -29,7 +29,9 @@ #include <assert.h> #include <glib-object.h> #include <stdbool.h> -#include <gdk/gdk.h> +#ifdef INCLUDE_GTK_SUPPORT +# include <gdk/gdk.h> +#endif @@ -85,26 +87,21 @@ bool register_python_module_object(PyObject *, PyTypeObject *); #name "(" args ")\n--\n\n" doc \ } -#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \ - { \ - #name, (PyCFunction)py_return_none, \ - flags, \ - #name "(" args ")\n--\n\n" doc \ +#define PYTHON_WRAPPER_DEF_WITH(name, args, flags, defcb, doc) \ + { \ + #name, (PyCFunction)defcb, \ + flags, \ + #name "(" args ")\n--\n\n" doc \ } -#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc)\ - { \ - #name, (PyCFunction)py_return_false, \ - flags, \ - #name "(" args ")\n--\n\n" doc \ - } +#define PYTHON_VOID_WRAPPER_DEF(name, args, flags, doc) \ + PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_none, doc) -#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc)\ - { \ - #name, (PyCFunction)py_return_true, \ - flags, \ - #name "(" args ")\n--\n\n" doc \ - } +#define PYTHON_FALSE_WRAPPER_DEF(name, args, flags, doc) \ + PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_false, doc) + +#define PYTHON_TRUE_WRAPPER_DEF(name, args, flags, doc) \ + PYTHON_WRAPPER_DEF_WITH(name, args, flags, py_return_true, doc) /** * Il ne semble pas exister de moyen de déterminer @@ -158,6 +155,34 @@ bool register_python_module_object(PyObject *, PyTypeObject *); #define APPLY_ABSTRACT_FLAG(tp) tp->tp_new = PyBaseObject_Type.tp_new +/* Accompagne la création d'une instance dérivée en Python. */ +PyObject *python_constructor_with_dynamic_gtype(PyTypeObject *, GType, PyObject *, PyObject *); + +/* Accompagne la création d'une instance dérivée en Python. */ +PyObject *python_abstract_constructor_with_dynamic_gtype(PyTypeObject *, GType, GClassInitFunc, PyObject *, PyObject *); + + +#define CREATE_DYN_CONSTRUCTOR(pyname, gbase) \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \ +{ \ + PyObject *result; /* Objet à retourner */ \ + result = python_constructor_with_dynamic_gtype(type, gbase, args, kwds); \ + return result; \ +} + + +#define CREATE_DYN_ABSTRACT_CONSTRUCTOR(pyname, gbase, cinit) \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *, PyObject *, PyObject *); \ +static PyObject *py_ ## pyname ## _new(PyTypeObject *type, PyObject *args, PyObject *kwds) \ +{ \ + PyObject *result; /* Objet à retourner */ \ + result = python_abstract_constructor_with_dynamic_gtype(type, gbase, (GClassInitFunc)cinit, \ + args, kwds); \ + return result; \ +} + + /* Marque l'interdiction d'une instanciation depuis Python. */ PyObject *no_python_constructor_allowed(PyTypeObject *, PyObject *, PyObject *); @@ -200,16 +225,13 @@ PyTypeObject *define_python_dynamic_type(const PyTypeObject *); /* Enregistre correctement une surcouche de conversion GObject. */ -bool _register_class_for_pygobject(PyObject *, GType, PyTypeObject *, PyTypeObject *, ...); - -#define register_class_for_pygobject(dict, gtype, type, base) \ - _register_class_for_pygobject(dict, gtype, type, base, NULL) +bool register_class_for_pygobject(PyObject *, GType, PyTypeObject *); /* Enregistre correctement une interface GObject pour Python. */ bool register_interface_for_pygobject(PyObject *, GType, PyTypeObject *, const GInterfaceInfo *); /* Enregistre un type Python dérivant d'un type GLib dynamique. */ -bool register_class_for_dynamic_pygobject(GType, PyTypeObject *, PyTypeObject *); +bool register_class_for_dynamic_pygobject(GType, PyTypeObject *); /* Fait suivre à la partie GObject une initialisation nouvelle. */ int forward_pygobjet_init(PyObject *); @@ -220,12 +242,36 @@ int convert_to_gtype(PyObject *, void *); /* Tente de convertir en instance GObject. */ int convert_to_gobject(PyObject *, void *); +#ifdef INCLUDE_GTK_SUPPORT + /* Tente de convertir en instance de composant GTK. */ int convert_to_gtk_widget(PyObject *, void *); /* Tente de convertir en instance de conteneur GTK. */ int convert_to_gtk_container(PyObject *, void *); +#endif + + +#if !defined(INCLUDE_GTK_SUPPORT) && !defined(HOMEMADE_RGBA) + +# define HOMEMADE_RGBA + +/** + * Copie depuis /usr/include/gtk-3.0/gdk/gdkrgba.h + */ +typedef struct _GdkRGBA +{ + gdouble red; + gdouble green; + gdouble blue; + gdouble alpha; + +} GdkRGBA; + +#endif + + /* Construit un objet Python pour une couleur RGBA. */ PyObject *create_gdk_rgba(const GdkRGBA *); @@ -261,6 +307,41 @@ int convert_to_gdk_rgba(PyObject *, void *); }) +#define TRANSLATE_NUMERIC_FIELD(dict, base, field) \ + ({ \ + PyObject *__attrib; \ + __attrib = PyLong_FromUnsignedLongLong(base->field); \ + Py_INCREF(__attrib); \ + ADD_FIELD_TRANSLATION(dict, #field, __attrib); \ + }) + + +#define RETRIEVE_NUMERIC_FIELD(dict, base, field) \ + ({ \ + bool __status; \ + PyObject *__attrib; \ + __status = false; \ + __attrib = PyDict_GetItemString(dict, #field); \ + if (__attrib != NULL && PyLong_Check(__attrib)) \ + { \ + base->field = PyLong_AsUnsignedLongLong(__attrib); \ + __status = (PyErr_Occurred() == NULL); \ + } \ + __status; \ + }) + + +#define TRANSLATE_BYTES_FIELD(dict, base, field, len) \ + ({ \ + void *__data; \ + PyObject *__attrib; \ + __data = (void *)&base->field; \ + __attrib = PyBytes_FromStringAndSize(__data, len); \ + Py_INCREF(__attrib); \ + ADD_FIELD_TRANSLATION(dict, #field, __attrib); \ + }) + + #define TRANSLATE_STRING_FIELD(dict, base, field) \ ({ \ PyObject *__attrib; \ @@ -308,20 +389,46 @@ int convert_to_gdk_rgba(PyObject *, void *); }) /* Officialise un groupe de constantes avec sémentique. */ -bool _attach_constants_group(const char *, PyObject *, bool, const char *, PyObject *, const char *); - -#define attach_constants_group_to_type(type, flags, name, values, doc) \ - _attach_constants_group(type->tp_name, type->tp_dict, flags, name, values, doc) - -#define attach_constants_group_to_module(mod, flags, name, values, doc) \ - ({ \ - bool __result; \ - const char *__owner; \ - PyObject *__dict; \ - __owner = PyModule_GetName(mod); \ - __dict = PyModule_GetDict(mod); \ - __result = _attach_constants_group(__owner, __dict, flags, name, values, doc); \ - __result; \ +PyObject *_attach_constants_group(const char *, PyObject *, bool, const char *, PyObject *, const char *); + +#define attach_constants_group_to_type(type, flags, name, values, doc) \ + ({ \ + bool __result; \ + PyObject *__new; \ + __new = _attach_constants_group(type->tp_name, type->tp_dict, flags, name, values, \ + doc); \ + __result = (__new != NULL); \ + Py_XDECREF(__new); \ + __result; \ + }) + +#define attach_constants_group_to_module(mod, flags, name, values, doc) \ + ({ \ + bool __result; \ + const char *__owner; \ + PyObject *__dict; \ + PyObject *__new; \ + __owner = PyModule_GetName(mod); \ + __dict = PyModule_GetDict(mod); \ + __new = _attach_constants_group(__owner, __dict, flags, name, values, doc); \ + __result = (__new != NULL); \ + Py_XDECREF(__new); \ + __result; \ + }) + +/* Officialise un groupe de constantes avec lien GLib. */ +PyObject *_attach_constants_group_with_pyg_enum(const char *, PyObject *, bool, const char *, PyObject *, const char *, GType); + + +#define attach_constants_group_to_type_with_pyg_enum(type, flags, name, values, doc, gtype) \ + ({ \ + bool __result; \ + PyObject *__new; \ + __new = _attach_constants_group_with_pyg_enum(type->tp_name, type->tp_dict, flags, \ + name, values, doc, gtype); \ + __result = (__new != NULL); \ + Py_XDECREF(__new); \ + __result; \ }) /* Traduit une valeur constante C en équivalent Python. */ diff --git a/plugins/pychrysalide/mangling/Makefile.am b/plugins/pychrysalide/mangling/Makefile.am index bec4baf..640e420 100644 --- a/plugins/pychrysalide/mangling/Makefile.am +++ b/plugins/pychrysalide/mangling/Makefile.am @@ -1,23 +1,14 @@ noinst_LTLIBRARIES = libpychrysamangling.la -libpychrysamangling_la_SOURCES = \ - demangler.h demangler.c \ +libpychrysamangling_la_SOURCES = \ + demangler.h demangler.c \ module.h module.c -libpychrysamangling_la_LIBADD = - -libpychrysamangling_la_LDFLAGS = +libpychrysamangling_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysamangling_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/mangling/demangler.c b/plugins/pychrysalide/mangling/demangler.c index 87a19dc..fb90dca 100644 --- a/plugins/pychrysalide/mangling/demangler.c +++ b/plugins/pychrysalide/mangling/demangler.c @@ -25,6 +25,7 @@ #include "demangler.h" +#include <malloc.h> #include <pygobject.h> @@ -41,6 +42,9 @@ +/* Fournit la désignation interne du décodeur de désignations. */ +static PyObject *py_compiler_demangler_get_key(PyObject *, void *); + /* Tente de décoder une chaîne de caractères donnée en type. */ static PyObject *py_compiler_demangler_decode_type(PyObject *, PyObject *); @@ -51,6 +55,53 @@ static PyObject *py_compiler_demangler_decode_routine(PyObject *, PyObject *); /****************************************************************************** * * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la désignation interne du décodeur de désignations. * +* * +* Retour : Simple chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_compiler_demangler_get_key(PyObject *self, void *closure) +{ + PyObject *result; /* Instance Python à retourner */ + GCompDemangler *demangler; /* Version GLib de l'opérande */ + char *key; /* Désignation du décodeur */ + +#define COMPILER_DEMANGLER_KEY_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + key, py_compiler_demangler, \ + "Provide the small name used to identify the demangler," \ + " as a code string." \ +) + + demangler = G_COMP_DEMANGLER(pygobject_get(self)); + assert(demangler != NULL); + + key = g_compiler_demangler_get_key(demangler); + + if (key != NULL) + { + result = PyUnicode_FromString(key); + free(key); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : self = décodeur à solliciter pour l'opération. * * args = chaîne de caractères à décoder. * * * @@ -184,6 +235,7 @@ PyTypeObject *get_python_compiler_demangler_type(void) }; static PyGetSetDef py_comp_demangler_getseters[] = { + COMPILER_DEMANGLER_KEY_ATTRIB, { NULL } }; @@ -212,7 +264,7 @@ PyTypeObject *get_python_compiler_demangler_type(void) * * * Paramètres : module = module dont la définition est à compléter. * * * -* Description : Prend en charge l'objet 'pychrysalide.mangling.DexDemangler'.* +* Description : Prend en charge l'objet 'pychrysalide....CompDemangler'. * * * * Retour : Bilan de l'opération. * * * @@ -234,7 +286,7 @@ bool ensure_python_compiler_demangler_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_COMP_DEMANGLER, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_COMP_DEMANGLER, type)) return false; } diff --git a/plugins/pychrysalide/mangling/demangler.h b/plugins/pychrysalide/mangling/demangler.h index 0c31f7c..496aa21 100644 --- a/plugins/pychrysalide/mangling/demangler.h +++ b/plugins/pychrysalide/mangling/demangler.h @@ -34,7 +34,7 @@ /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_compiler_demangler_type(void); -/* Prend en charge l'objet 'pychrysalide.format.elf.ElfFormat'. */ +/* Prend en charge l'objet 'pychrysalide.mangling.CompDemangler'. */ bool ensure_python_compiler_demangler_is_registered(void); diff --git a/plugins/pychrysalide/plugins/Makefile.am b/plugins/pychrysalide/plugins/Makefile.am index 8a0d4c9..bb9ed5d 100644 --- a/plugins/pychrysalide/plugins/Makefile.am +++ b/plugins/pychrysalide/plugins/Makefile.am @@ -1,25 +1,16 @@ noinst_LTLIBRARIES = libpychrysaplugins.la -libpychrysaplugins_la_SOURCES = \ - constants.h constants.c \ - plugin.h plugin.c \ - module.h module.c \ +libpychrysaplugins_la_SOURCES = \ + constants.h constants.c \ + plugin.h plugin.c \ + module.h module.c \ translate.h translate.c -libpychrysaplugins_la_LIBADD = - -libpychrysaplugins_la_LDFLAGS = +libpychrysaplugins_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_INTERPRETER_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libpychrysaplugins_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - -SUBDIRS = diff --git a/plugins/pychrysalide/plugins/plugin.c b/plugins/pychrysalide/plugins/plugin.c index bd9cdfe..b013345 100644 --- a/plugins/pychrysalide/plugins/plugin.c +++ b/plugins/pychrysalide/plugins/plugin.c @@ -51,21 +51,31 @@ /* ------------------------ GLUE POUR CREATION DEPUIS PYTHON ------------------------ */ -/* Accompagne la création d'une instance dérivée en Python. */ -static PyObject *py_plugin_module_new(PyTypeObject *, PyObject *, PyObject *); - /* Initialise la classe des greffons d'extension. */ static void py_plugin_module_init_gclass(GPluginModuleClass *, gpointer); +CREATE_DYN_ABSTRACT_CONSTRUCTOR(plugin_module, G_TYPE_PLUGIN_MODULE, py_plugin_module_init_gclass); + /* Initialise une instance sur la base du dérivé de GObject. */ static int py_plugin_module_init(PyObject *self, PyObject *args, PyObject *kwds); /* Encadre une étape de la vie d'un greffon. */ static bool py_plugin_module_manage_wrapper(GPluginModule *); +/* Assiste la désactivation d'un greffon. */ +static bool py_plugin_module_exit(GPluginModule *); + /* Accompagne la fin du chargement des modules natifs. */ static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *, PluginAction); +/* Fournit le nom brut associé au greffon par défaut. */ +static PyObject *py_plugin_module_get_modname_by_default(PyObject *, PyObject *); + +/* Fournit le nom brut associé au greffon. */ +static char *py_plugin_module_get_modname_wrapper(const GPluginModule *); + +#ifdef INCLUDE_GTK_SUPPORT + /* Complète une liste de resources pour thème. */ static void py_plugin_module_include_theme_wrapper(const GPluginModule *, PluginAction, gboolean, char ***, size_t *); @@ -75,6 +85,8 @@ static void py_plugin_module_notify_panel_creation_wrapper(const GPluginModule * /* Rend compte d'un affichage ou d'un retrait de panneau. */ static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *, PluginAction, GPanelItem *, bool); +#endif + /* Procède à une opération liée à un contenu binaire. */ static void py_plugin_module_handle_binary_content_wrapper(const GPluginModule *, PluginAction, GBinContent *, wgroup_id_t, GtkStatusStack *); @@ -98,42 +110,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule * -/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ - - -/* Ligne de représentation de code binaire (instance) */ -struct _GPythonPlugin -{ - GPluginModule parent; /* Instance parente */ - -}; - - -/* Ligne de représentation de code binaire (classe) */ -struct _GPythonPluginClass -{ - GPluginModuleClass parent; /* Classe parente */ - -}; - - -/* Initialise la classe des greffons Python. */ -static void g_python_plugin_class_init(GPythonPluginClass *); - -/* Initialise l'instance d'un greffon Python. */ -static void g_python_plugin_init(GPythonPlugin *); - -/* Supprime toutes les références externes. */ -static void g_python_plugin_dispose(GPythonPlugin *); - -/* Description : Procède à la libération totale de la mémoire. */ -static void g_python_plugin_finalize(GPythonPlugin *); - -/* Fournit le nom brut associé au greffon. */ -static char *g_python_plugin_get_modname(const GPythonPlugin *); - - - /* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ @@ -161,69 +137,6 @@ static PyObject *py_plugin_module_get_interface(PyObject *, void *); /****************************************************************************** * * -* Paramètres : type = type du nouvel objet à mettre en place. * -* args = éventuelle liste d'arguments. * -* kwds = éventuel dictionnaire de valeurs mises à disposition. * -* * -* Description : Accompagne la création d'une instance dérivée en Python. * -* * -* Retour : Nouvel objet Python mis en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_plugin_module_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Objet à retourner */ - PyTypeObject *base; /* Type de base à dériver */ - bool first_time; /* Evite les multiples passages*/ - GType gtype; /* Nouveau type de processeur */ - bool status; /* Bilan d'un enregistrement */ - - /* Validations diverses */ - - base = get_python_plugin_module_type(); - - if (type == base) - { - result = NULL; - PyErr_Format(PyExc_RuntimeError, _("%s is an abstract class"), type->tp_name); - goto exit; - } - - /* Mise en place d'un type dédié */ - - first_time = (g_type_from_name(type->tp_name) == 0); - - gtype = build_dynamic_type(G_TYPE_PYTHON_PLUGIN, type->tp_name, - (GClassInitFunc)py_plugin_module_init_gclass, NULL, NULL); - - if (first_time) - { - status = register_class_for_dynamic_pygobject(gtype, type, base); - - if (!status) - { - result = NULL; - goto exit; - } - - } - - /* On crée, et on laisse ensuite la main à PyGObject_Type.tp_init() */ - - result = PyType_GenericNew(type, args, kwds); - - exit: - - return result; - -} - - -/****************************************************************************** -* * * Paramètres : class = classe à initialiser. * * unused = données non utilisées ici. * * * @@ -239,13 +152,17 @@ static void py_plugin_module_init_gclass(GPluginModuleClass *class, gpointer unu { class->init = NULL; class->manage = py_plugin_module_manage_wrapper; - class->exit = NULL; + class->exit = py_plugin_module_exit; class->plugins_loaded = py_plugin_module_notify_plugins_loaded_wrapper; + class->get_modname = py_plugin_module_get_modname_wrapper; + +#ifdef INCLUDE_GTK_SUPPORT class->include_theme = py_plugin_module_include_theme_wrapper; class->notify_panel = py_plugin_module_notify_panel_creation_wrapper; class->notify_docking = py_plugin_module_notify_panel_docking_wrapper; +#endif class->handle_content = py_plugin_module_handle_binary_content_wrapper; class->handle_loaded = py_plugin_module_handle_loaded_content_wrapper; @@ -498,6 +415,51 @@ static bool py_plugin_module_manage_wrapper(GPluginModule *plugin) /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * +* * +* Description : Assiste la désactivation d'un greffon. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool py_plugin_module_exit(GPluginModule *plugin) +{ + bool result; /* Bilan à faire remonter */ + plugin_interface *final; /* Interface finale conservée */ + + result = true; + + final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; + + if (final != NULL) + { + if (final->name != NULL) free(final->name); + if (final->desc != NULL) free(final->desc); + if (final->version != NULL) free(final->version); + if (final->url != NULL) free(final->url); + + assert(final->required_count == 1); + + if (final->required != NULL) + free(final->required); + + if (final->actions != NULL) + free(final->actions); + + free(final); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * * * Description : Accompagne la fin du chargement des modules natifs. * @@ -555,6 +517,103 @@ static void py_plugin_module_notify_plugins_loaded_wrapper(GPluginModule *plugin /****************************************************************************** * * +* Paramètres : self = objet Python concerné par l'appel. * +* args = arguments fournis à l'appel. * +* * +* Description : Fournit le nom brut associé au greffon par défaut. * +* * +* Retour : Désignation brute du greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_plugin_module_get_modname_by_default(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GPluginModule *plugin; /* Version native du greffon */ + char *path; /* Chemin à traiter */ + + plugin = G_PLUGIN_MODULE(pygobject_get(self)); + + path = strdup(g_plugin_module_get_filename(plugin)); + + result = PyUnicode_FromString(basename(path)); + + free(path); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : plugin = greffon à valider. * +* * +* Description : Fournit le nom brut associé au greffon. * +* * +* Retour : Désignation brute du greffon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static char *py_plugin_module_get_modname_wrapper(const GPluginModule *plugin) +{ + char *result; /* Désignation brute à renvoyer*/ + PyGILState_STATE gstate; /* Sauvegarde d'environnement */ + PyObject *pyobj; /* Objet Python concerné */ + PyObject *pyret; /* Bilan d'exécution */ + +#define PLUGIN_MODULE_GET_MODNAME_WRAPPER PYTHON_WRAPPER_DEF_WITH \ +( \ + _get_modname, "$self, /", \ + METH_VARARGS, py_plugin_module_get_modname_by_default, \ + "(Abstract) method providing the raw module name of the plugin.\n" \ + " loaded.\n" \ + "\n" \ + "The result should be a short string value.\n" \ + "\n" \ + "A default implementation builds the module name from the Python" \ + " script filename." \ +) + + result = NULL; + + gstate = PyGILState_Ensure(); + + pyobj = pygobject_new(G_OBJECT(plugin)); + + if (has_python_method(pyobj, "_get_modname")) + { + pyret = run_python_method(pyobj, "_get_modname", NULL); + + if (!PyUnicode_Check(pyret)) + g_plugin_module_log_variadic_message(plugin, LMT_ERROR, + _("The returned raw name must be a string")); + + else + result = strdup(PyUnicode_DATA(pyret)); + + Py_XDECREF(pyret); + + } + + Py_DECREF(pyobj); + + PyGILState_Release(gstate); + + return result; + +} + + +#ifdef INCLUDE_GTK_SUPPORT + + +/****************************************************************************** +* * * Paramètres : plugin = greffon à manipuler. * * action = type d'action attendue. * * dark = indique une préférence pour la variante foncée. * @@ -783,6 +842,9 @@ static void py_plugin_module_notify_panel_docking_wrapper(const GPluginModule *p } +#endif + + /****************************************************************************** * * * Paramètres : plugin = greffon à manipuler. * @@ -1300,262 +1362,6 @@ static void py_plugin_module_detect_external_tools_wrapper(const GPluginModule * /* ---------------------------------------------------------------------------------- */ -/* INTERFACE INTERNE POUR GREFFONS PYTHON */ -/* ---------------------------------------------------------------------------------- */ - - -/* Indique le type défini par la GLib pour le greffon Python. */ -G_DEFINE_TYPE(GPythonPlugin, g_python_plugin, G_TYPE_PLUGIN_MODULE); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des greffons Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_class_init(GPythonPluginClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - GPluginModuleClass *plugin; /* Version parente de la classe*/ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_python_plugin_dispose; - object->finalize = (GObjectFinalizeFunc)g_python_plugin_finalize; - - plugin = G_PLUGIN_MODULE_CLASS(klass); - - plugin->get_modname = (pg_get_modname_fc)g_python_plugin_get_modname; - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance à initialiser. * -* * -* Description : Initialise l'instance d'un greffon Python. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_init(GPythonPlugin *plugin) -{ - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_dispose(GPythonPlugin *plugin) -{ -#if 0 - PyThreadState *tstate; /* Contexte d'environnement */ - - /** - * Cf. https://docs.python.org/3/c-api/init.html#thread-state-and-the-global-interpreter-lock - * - * Cependant, comme on se trouve à priori dans le thread principal de l'interpréteur, - * PyGILState_Ensure() ne pose aucun verrou. Ce qui aboutit à la situation suivante : - * - * Fatal Python error: drop_gil: GIL is not locked - * - * On peut forcer les choses avec PyEval_AcquireLock(), mais cette fonction est marquée - * comme dépréciée depuis Python 3.2. - * - * Donc on choisit les alternatives officielles. - * - * Cependant, PyThreadState_Get() renvoit l'erreur suivante : - * - * Fatal Python error: PyThreadState_Get: no current thread - * - * Donc on se rabat sur une sauvegarde, qui n'est initialisée que lorsque l'interpréteur - * est intégré dans l'éditeur. - */ - - tstate = get_pychrysalide_main_tstate(); - - if (tstate != NULL) - PyEval_RestoreThread(tstate); - - if (tstate != NULL) - PyEval_SaveThread(); -#endif - - G_OBJECT_CLASS(g_python_plugin_parent_class)->dispose(G_OBJECT(plugin)); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_python_plugin_finalize(GPythonPlugin *plugin) -{ - plugin_interface *final; /* Interface finale conservée */ - - final = (plugin_interface *)G_PLUGIN_MODULE(plugin)->interface; - - if (final != NULL) - { - if (final->name != NULL) free(final->name); - if (final->desc != NULL) free(final->desc); - if (final->version != NULL) free(final->version); - if (final->url != NULL) free(final->url); - - assert(final->required_count == 1); - - if (final->required != NULL) - free(final->required); - - if (final->actions != NULL) - free(final->actions); - - free(final); - - } - - G_OBJECT_CLASS(g_python_plugin_parent_class)->finalize(G_OBJECT(plugin)); - -} - - -/****************************************************************************** -* * -* Paramètres : plugin = greffon à valider. * -* * -* Description : Fournit le nom brut associé au greffon. * -* * -* Retour : Désignation brute du greffon. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static char *g_python_plugin_get_modname(const GPythonPlugin *plugin) -{ - char *result; /* Désignation brute à renvoyer*/ - char *path; /* Chemin à traiter */ - - path = strdup(g_plugin_module_get_filename(G_PLUGIN_MODULE(plugin))); - - result = strdup(basename(path)); - - free(path); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : modname = nom du module à charger. * -* filename = chemin d'accès au code Python à charger. * -* * -* Description : Crée un greffon à partir de code Python. * -* * -* Retour : Adresse de la structure mise en place ou NULL si erreur. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GPluginModule *g_python_plugin_new(const char *modname, const char *filename) -{ - GPythonPlugin *result; /* Structure à retourner */ - PyObject *name; /* Chemin d'accès pour Python */ - PyObject *module; /* Script Python chargé */ - PyObject *dict; /* Dictionnaire associé */ - PyObject *class; /* Classe à instancier */ - PyObject *instance; /* Instance Python du greffon */ - - name = PyUnicode_FromString(modname); - if (name == NULL) goto bad_exit; - - module = PyImport_Import(name); - Py_DECREF(name); - - if (module == NULL) goto no_import; - - dict = PyModule_GetDict(module); - class = PyDict_GetItemString(dict, "AutoLoad"); - - if (class == NULL) goto no_class; - if (!PyType_Check(class->ob_type)) goto no_class; - - instance = PyObject_CallFunction(class, NULL); - if (instance == NULL) goto no_instance; - - result = G_PYTHON_PLUGIN(pygobject_get(instance)); - - G_PLUGIN_MODULE(result)->filename = strdup(filename); - - /** - * L'instance Python et l'objet GLib résultante sont un même PyGObject. - * - * Donc pas besoin de toucher au comptage des références ici, la libération - * se réalisera à la fin, quand l'objet GLib sera libéré. - */ - - Py_DECREF(module); - - return G_PLUGIN_MODULE(result); - - no_instance: - - log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance")); - - no_class: - - if (class == NULL) - log_plugin_simple_message(LMT_ERROR, - _("An error occured when looking for the 'AutoLoad': item not found!")); - - no_import: - - Py_XDECREF(module); - - log_pychrysalide_exception(_("An error occured when importing '%s'"), modname); - - bad_exit: - - return NULL; - -} - - - -/* ---------------------------------------------------------------------------------- */ /* MODULE PYTHON POUR LES SCRIPTS */ /* ---------------------------------------------------------------------------------- */ @@ -1865,9 +1671,12 @@ PyTypeObject *get_python_plugin_module_type(void) static PyMethodDef py_plugin_module_methods[] = { PLUGIN_MODULE_MANAGE_WRAPPER, PLUGIN_MODULE_NOTIFY_PLUGINS_LOADED_WRAPPER, + PLUGIN_MODULE_GET_MODNAME_WRAPPER, +#ifdef INCLUDE_GTK_SUPPORT PLUGIN_MODULE_INCLUDE_THEME_WRAPPER, PLUGIN_MODULE_ON_PANEL_CREATION_WRAPPER, PLUGIN_MODULE_ON_PANEL_DOCKING_WRAPPER, +#endif PLUGIN_MODULE_HANDLE_BINARY_CONTENT_WRAPPER, PLUGIN_MODULE_HANDLE_LOADED_CONTENT_WRAPPER, PLUGIN_MODULE_HANDLE_BINARY_FORMAT_ANALYSIS_WRAPPER, @@ -1938,7 +1747,7 @@ bool ensure_python_plugin_module_is_registered(void) dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_PYTHON_PLUGIN, type, &PyGObject_Type)) + if (!register_class_for_pygobject(dict, G_TYPE_PLUGIN_MODULE, type)) return false; if (!define_plugin_module_constants(type)) @@ -1949,3 +1758,80 @@ bool ensure_python_plugin_module_is_registered(void) return true; } + + +/****************************************************************************** +* * +* Paramètres : modname = nom du module à charger. * +* filename = chemin d'accès au code Python à charger. * +* * +* Description : Crée un greffon à partir de code Python. * +* * +* Retour : Adresse de la structure mise en place ou NULL si erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GPluginModule *create_python_plugin(const char *modname, const char *filename) +{ + GPluginModule *result; /* Structure à retourner */ + PyObject *name; /* Chemin d'accès pour Python */ + PyObject *module; /* Script Python chargé */ + PyObject *dict; /* Dictionnaire associé */ + PyObject *class; /* Classe à instancier */ + PyObject *instance; /* Instance Python du greffon */ + + name = PyUnicode_FromString(modname); + if (name == NULL) goto bad_exit; + + module = PyImport_Import(name); + Py_DECREF(name); + + if (module == NULL) goto no_import; + + dict = PyModule_GetDict(module); + class = PyDict_GetItemString(dict, "AutoLoad"); + + if (class == NULL) goto no_class; + if (!PyType_Check(class->ob_type)) goto no_class; + + instance = PyObject_CallFunction(class, NULL); + if (instance == NULL) goto no_instance; + + result = G_PLUGIN_MODULE(pygobject_get(instance)); + + result->filename = strdup(filename); + + /** + * L'instance Python et l'objet GLib résultante sont un même PyGObject. + * + * Donc pas besoin de toucher au comptage des références ici, la libération + * se réalisera à la fin, quand l'objet GLib sera libéré. + */ + + Py_DECREF(module); + + return result; + + no_instance: + + log_pychrysalide_exception(_("An error occured when building the 'AutoLoad' instance")); + + no_class: + + if (class == NULL) + log_plugin_simple_message(LMT_ERROR, + _("An error occured when looking for the 'AutoLoad': item not found!")); + + no_import: + + Py_XDECREF(module); + + log_pychrysalide_exception(_("An error occured when importing '%s'"), modname); + + bad_exit: + + return NULL; + +} diff --git a/plugins/pychrysalide/plugins/plugin.h b/plugins/pychrysalide/plugins/plugin.h index ff805f4..ad54b8e 100644 --- a/plugins/pychrysalide/plugins/plugin.h +++ b/plugins/pychrysalide/plugins/plugin.h @@ -35,41 +35,15 @@ -/* --------------------- INTERFACE INTERNE POUR GREFFONS PYTHON --------------------- */ - - -#define G_TYPE_PYTHON_PLUGIN (g_python_plugin_get_type()) -#define G_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_PYTHON_PLUGIN, GPythonPlugin)) -#define G_IS_PYTHON_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_PYTHON_PLUGIN)) -#define G_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass)) -#define G_IS_PYTHON_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_PYTHON_PLUGIN)) -#define G_PYTHON_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_PYTHON_PLUGIN, GPythonPluginClass)) - - -/* Ligne de représentation de code binaire (instance) */ -typedef struct _GPythonPlugin GPythonPlugin; - -/* Ligne de représentation de code binaire (classe) */ -typedef struct _GPythonPluginClass GPythonPluginClass; - - -/* Indique le type défini par la GLib pour le greffon Python. */ -GType g_python_plugin_get_type(void); - -/* Crée un greffon à partir de code Python. */ -GPluginModule *g_python_plugin_new(const char *, const char *); - - - -/* ------------------------- MODULE PYTHON POUR LES SCRIPTS ------------------------- */ - - /* Fournit un accès à une définition de type à diffuser. */ PyTypeObject *get_python_plugin_module_type(void); /* Prend en charge l'objet 'pychrysalide.plugins.PluginModule'. */ bool ensure_python_plugin_module_is_registered(void); +/* Crée un greffon à partir de code Python. */ +GPluginModule *create_python_plugin(const char *, const char *); + #endif /* _PLUGINS_PYCHRYSALIDE_PLUGINS_PLUGIN_H */ diff --git a/plugins/pychrysalide/weak.h b/plugins/pychrysalide/weak.h index 01885b0..767873f 100644 --- a/plugins/pychrysalide/weak.h +++ b/plugins/pychrysalide/weak.h @@ -26,10 +26,10 @@ #define _PLUGINS_PYCHRYSALIDE_WEAK_H -#include <gtkext/gtkstatusstack.h> - +#include <glibext/notifier.h> +#if 0 /* Démarre le suivi d'une nouvelle activité. */ activity_id_t gtk_status_stack_add_activity(GtkStatusStack *, const char *, unsigned long) __attribute__((weak)); @@ -44,7 +44,7 @@ void gtk_status_stack_update_activity_value(GtkStatusStack *, activity_id_t, uns /* Met fin au suivi d'une activité donnée. */ void gtk_status_stack_remove_activity(GtkStatusStack *, activity_id_t) __attribute__((weak)); - +#endif #endif /* _PLUGINS_PYCHRYSALIDE_WEAK_H */ diff --git a/plugins/python/cglimpse/panel.py b/plugins/python/cglimpse/panel.py index a195b0d..e2dc035 100644 --- a/plugins/python/cglimpse/panel.py +++ b/plugins/python/cglimpse/panel.py @@ -118,7 +118,8 @@ class CGlimpsePanel(PanelItem, UpdatablePanel): assert(uid == 0) - self.switch_to_updating_mask() + # Reduce the rendering concurrency between the GTK main loop and this thread + #self.switch_to_updating_mask() def _process(self, uid, status, id, data): @@ -137,7 +138,8 @@ class CGlimpsePanel(PanelItem, UpdatablePanel): assert(uid == 0) - self.switch_to_updated_content() + # Reduce the rendering concurrency between the GTK main loop and this thread + # self.switch_to_updated_content() def _clean_data(self, uid, data): diff --git a/plugins/python/scripting/core.py b/plugins/python/scripting/core.py index ff912ed..135edb4 100644 --- a/plugins/python/scripting/core.py +++ b/plugins/python/scripting/core.py @@ -1,4 +1,7 @@ +import gi +gi.require_version('Gtk', '3.0') + from gi.repository import GLib, Gtk import os diff --git a/plugins/readdex/Makefile.am b/plugins/readdex/Makefile.am index b21f855..b2099fb 100644 --- a/plugins/readdex/Makefile.am +++ b/plugins/readdex/Makefile.am @@ -15,13 +15,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN' endif -libreaddex_la_SOURCES = \ - class.h class.c \ - code.h code.c \ - header.h header.c \ - ids.h ids.c \ +libreaddex_la_SOURCES = \ + class.h class.c \ + code.h code.c \ + header.h header.c \ + ids.h ids.c \ reader.h reader.c +libreaddex_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libreaddex_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -33,8 +35,3 @@ libreaddex_la_LDFLAGS = \ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libreaddex_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/readdex/class.h b/plugins/readdex/class.h index c7c34b0..a2c2bee 100644 --- a/plugins/readdex/class.h +++ b/plugins/readdex/class.h @@ -26,7 +26,7 @@ #include <format/preload.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> #include <plugins/dex/format.h> diff --git a/plugins/readdex/ids.h b/plugins/readdex/ids.h index 3a902cd..85495d1 100644 --- a/plugins/readdex/ids.h +++ b/plugins/readdex/ids.h @@ -26,7 +26,7 @@ #include <format/preload.h> -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> #include <plugins/dex/format.h> diff --git a/plugins/readelf/Makefile.am b/plugins/readelf/Makefile.am index 0ca002b..7e662ee 100644 --- a/plugins/readelf/Makefile.am +++ b/plugins/readelf/Makefile.am @@ -15,13 +15,15 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN' endif -libreadelf_la_SOURCES = \ - header.h header.c \ - program.h program.c \ - reader.h reader.c \ - section.h section.c \ +libreadelf_la_SOURCES = \ + header.h header.c \ + program.h program.c \ + reader.h reader.c \ + section.h section.c \ strtab.h strtab.c +libreadelf_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libreadelf_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -29,11 +31,7 @@ libreadelf_la_LDFLAGS = \ -L$(top_srcdir)/plugins/fmtp/.libs -lfmtp \ $(RUN_PATH) + devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libreadelf_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/readmc/Makefile.am b/plugins/readmc/Makefile.am index fa13fb2..51a8552 100644 --- a/plugins/readmc/Makefile.am +++ b/plugins/readmc/Makefile.am @@ -15,14 +15,16 @@ RUN_PATH = -Wl,-rpath,'$$ORIGIN' endif -libreadmc_la_SOURCES = \ - header.h header.c \ - reader.h reader.c \ - text.h text.c \ - v21.h v21.c \ - v23.h v23.c \ +libreadmc_la_SOURCES = \ + header.h header.c \ + reader.h reader.c \ + text.h text.c \ + v21.h v21.c \ + v23.h v23.c \ v24.h v24.c +libreadmc_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libreadmc_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -34,8 +36,3 @@ libreadmc_la_LDFLAGS = \ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libreadmc_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/ropgadgets/Makefile.am b/plugins/ropgadgets/Makefile.am index f23e054..bec050e 100644 --- a/plugins/ropgadgets/Makefile.am +++ b/plugins/ropgadgets/Makefile.am @@ -22,6 +22,8 @@ libropgadgets_la_SOURCES = \ plugin.h plugin.c \ select.h select.c +libropgadgets_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libropgadgets_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -32,8 +34,3 @@ libropgadgets_la_LDFLAGS = \ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libropgadgets_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/ropgadgets/plugin.c b/plugins/ropgadgets/plugin.c index 836717c..938a04c 100644 --- a/plugins/ropgadgets/plugin.c +++ b/plugins/ropgadgets/plugin.c @@ -24,7 +24,6 @@ #include "plugin.h" -#include <config.h> #include <i18n.h> @@ -36,7 +35,7 @@ #include "select.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ diff --git a/plugins/ropgadgets/select.c b/plugins/ropgadgets/select.c index a45f043..c0cf08d 100644 --- a/plugins/ropgadgets/select.c +++ b/plugins/ropgadgets/select.c @@ -35,10 +35,12 @@ #include <i18n.h> +#include <analysis/binary.h> #include <analysis/contents/file.h> #include <core/global.h> #include <common/cpp.h> #include <common/extstr.h> +#include <core/columns.h> #include <core/processors.h> #include <format/known.h> #include <gui/core/global.h> diff --git a/plugins/winordinals/Makefile.am b/plugins/winordinals/Makefile.am index f9ff14f..592d38a 100644 --- a/plugins/winordinals/Makefile.am +++ b/plugins/winordinals/Makefile.am @@ -50,6 +50,8 @@ libwinordinals_la_SOURCES = \ libwinordinals_la_LIBADD = \ $(PYTHON3_LIBADD) +libwinordinals_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src + libwinordinals_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ @@ -62,8 +64,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libwinordinals_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/winordinals/assign.h b/plugins/winordinals/assign.h index 20310d2..e88ee28 100644 --- a/plugins/winordinals/assign.h +++ b/plugins/winordinals/assign.h @@ -25,7 +25,7 @@ #define _PLUGINS_WINORDINALS_ASSIGN_H -#include <gtkext/gtkstatusstack.h> +#include <glibext/notifier.h> #include <plugins/pe/format.h> diff --git a/plugins/winordinals/core.c b/plugins/winordinals/core.c index a16c400..bae2d6d 100644 --- a/plugins/winordinals/core.c +++ b/plugins/winordinals/core.c @@ -31,12 +31,12 @@ #include "assign.h" -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -67,7 +67,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) result = true; -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS if (result) result = add_winordinals_module_to_python_module(); diff --git a/plugins/winordinals/python/Makefile.am b/plugins/winordinals/python/Makefile.am index a5f17a4..201650d 100644 --- a/plugins/winordinals/python/Makefile.am +++ b/plugins/winordinals/python/Makefile.am @@ -4,15 +4,10 @@ noinst_LTLIBRARIES = libwinordinalspython.la libwinordinalspython_la_SOURCES = \ module.h module.c -libwinordinalspython_la_LDFLAGS = +libwinordinalspython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libwinordinalspython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/yaml/Makefile.am b/plugins/yaml/Makefile.am index 9eee4ab..1165d7a 100644 --- a/plugins/yaml/Makefile.am +++ b/plugins/yaml/Makefile.am @@ -36,23 +36,24 @@ endif libyaml_la_SOURCES = \ + collection-int.h \ collection.h collection.c \ core.h core.c \ - line.h line.c \ node-int.h \ node.h node.c \ + pair-int.h \ pair.h pair.c \ - reader.h reader.c \ - scalar.h scalar.c \ - tree.h tree.c + parser.h parser.c libyaml_la_LIBADD = \ $(PYTHON3_LIBADD) +libyaml_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBYAML_CFLAGS) -I$(top_srcdir)/src + libyaml_la_LDFLAGS = \ -avoid-version \ -L$(top_srcdir)/src/.libs -lchrysacore \ - $(RUN_PATH) $(PYTHON3_LDFLAGS) + $(RUN_PATH) $(LIBYAML_LIBS) $(PYTHON3_LDFLAGS) devdir = $(includedir)/chrysalide/$(subdir) @@ -60,8 +61,4 @@ devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libyaml_la_SOURCES:%c=) -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) - SUBDIRS = $(PYTHON3_SUBDIRS) diff --git a/plugins/yaml/collection-int.h b/plugins/yaml/collection-int.h new file mode 100644 index 0000000..453976d --- /dev/null +++ b/plugins/yaml/collection-int.h @@ -0,0 +1,60 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * collection-int.h - prototypes internes pour la définition d'un noeud YAML + * + * Copyright (C) 2019-2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_YAML_COLLECTION_INT_H +#define PLUGINS_YAML_COLLECTION_INT_H + + +#include "collection.h" + + +#include "node-int.h" + + + +/* Collection de noeuds au format YAML (instance) */ +struct _GYamlCollection +{ + GYamlNode parent; /* A laisser en premier */ + + bool is_seq; /* Nature de la collection */ + + GYamlNode **nodes; /* Sous-noeuds intégrés */ + size_t count; /* Nombre de ces enfants */ + +}; + +/* Collection de noeuds au format YAML (classe) */ +struct _GYamlCollectionClass +{ + GYamlNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une collection de noeuds YAML. */ +bool g_yaml_collection_create(GYamlCollection *, bool); + + + +#endif /* PLUGINS_YAML_COLLECTION_INT_H */ diff --git a/plugins/yaml/collection.c b/plugins/yaml/collection.c index 376e894..cdc63d9 100644 --- a/plugins/yaml/collection.c +++ b/plugins/yaml/collection.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * collection.h - collection de noeuds Yaml de type "sequence" ou "mapping" + * collection.h - collection de noeuds YAML de type "sequence" ou "mapping" * * Copyright (C) 2019 Cyrille Bagard * @@ -27,34 +27,17 @@ #include <malloc.h> -#include "node-int.h" +#include "collection-int.h" -/* Collection de noeuds au format Yaml (instance) */ -struct _GYamlCollection -{ - GYamlNode parent; /* A laisser en premier */ - - bool is_seq; /* Nature de la collection */ - - GYamlNode **nodes; /* Sous-noeuds intégrés */ - size_t count; /* Nombre de ces enfants */ - -}; - -/* Collection de noeuds au format Yaml (classe) */ -struct _GYamlCollectionClass -{ - GYamlNodeClass parent; /* A laisser en premier */ - -}; +/* -------------------- DEFINITIONS PROPRES POUR LE SUPPORT YAML -------------------- */ -/* Initialise la classe des collections de noeuds Yaml. */ +/* Initialise la classe des collections de noeuds YAML. */ static void g_yaml_collection_class_init(GYamlCollectionClass *); -/* Initialise une instance de collection de noeuds Yaml. */ +/* Initialise une instance de collection de noeuds YAML. */ static void g_yaml_collection_init(GYamlCollection *); /* Supprime toutes les références externes. */ @@ -63,12 +46,22 @@ static void g_yaml_collection_dispose(GYamlCollection *); /* Procède à la libération totale de la mémoire. */ static void g_yaml_collection_finalize(GYamlCollection *); -/* Recherche les noeuds correspondant à un chemin. */ -static void g_yaml_collection_find_by_path(const GYamlCollection *, const char *, bool, GYamlNode ***, size_t *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Recherche le premier noeud correspondant à un chemin. */ +static GYamlNode *g_yaml_collection_find_first_by_path(GYamlCollection *, const char *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITIONS PROPRES POUR LE SUPPORT YAML */ +/* ---------------------------------------------------------------------------------- */ + -/* Indique le type défini pour une collection de noeuds Yaml. */ +/* Indique le type défini pour une collection de noeuds YAML. */ G_DEFINE_TYPE(GYamlCollection, g_yaml_collection, G_TYPE_YAML_NODE); @@ -76,7 +69,7 @@ G_DEFINE_TYPE(GYamlCollection, g_yaml_collection, G_TYPE_YAML_NODE); * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des collections de noeuds Yaml. * +* Description : Initialise la classe des collections de noeuds YAML. * * * * Retour : - * * * @@ -96,7 +89,7 @@ static void g_yaml_collection_class_init(GYamlCollectionClass *klass) node = G_YAML_NODE_CLASS(klass); - node->find = (find_yaml_node_fc)g_yaml_collection_find_by_path; + node->find = (find_first_yaml_node_fc)g_yaml_collection_find_first_by_path; } @@ -105,7 +98,7 @@ static void g_yaml_collection_class_init(GYamlCollectionClass *klass) * * * Paramètres : collec = instance à initialiser. * * * -* Description : Initialise une instance de collection de noeuds Yaml. * +* Description : Initialise une instance de collection de noeuds YAML. * * * * Retour : - * * * @@ -173,7 +166,7 @@ static void g_yaml_collection_finalize(GYamlCollection *collec) * * * Paramètres : seq = indique la nature de la future collection. * * * -* Description : Construit une collection de noeuds Yaml. * +* Description : Construit une collection de noeuds YAML. * * * * Retour : Instance mise en place ou NULL en cas d'échec. * * * @@ -187,7 +180,34 @@ GYamlCollection *g_yaml_collection_new(bool seq) result = g_object_new(G_TYPE_YAML_COLLEC, NULL); - result->is_seq = seq; + if (!g_yaml_collection_create(result, seq)) + g_clear_object(&result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : collec = noeud d'arborescence YAML à initialiser pleinement. * +* seq = indique la nature de la future collection. * +* * +* Description : Met en place une collection de noeuds YAML. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_yaml_collection_create(GYamlCollection *collec, bool seq) +{ + bool result; /* Bilan à retourner */ + + result = true; + + collec->is_seq = seq; return result; @@ -196,9 +216,9 @@ GYamlCollection *g_yaml_collection_new(bool seq) /****************************************************************************** * * -* Paramètres : collec = noeud d'arborescence Yaml à consulter. * +* Paramètres : collec = noeud d'arborescence YAML à consulter. * * * -* Description : Indique la nature d'une collection Yaml. * +* Description : Indique la nature d'une collection YAML. * * * * Retour : Nature de la collection. * * * @@ -219,10 +239,10 @@ bool g_yaml_collection_is_sequence(const GYamlCollection *collec) /****************************************************************************** * * -* Paramètres : collec = collection de noeuds Yaml à compléter. * +* Paramètres : collec = collection de noeuds YAML à compléter. * * node = noeud à rattacher. * * * -* Description : Ajoute un noeud à une collection de noeuds Yaml. * +* Description : Ajoute un noeud à une collection de noeuds YAML. * * * * Retour : - * * * @@ -242,12 +262,12 @@ void g_yaml_collection_add_node(GYamlCollection *collec, GYamlNode *node) /****************************************************************************** * * -* Paramètres : collec = noeud d'arborescence Yaml à consulter. * +* Paramètres : collec = noeud d'arborescence YAML à consulter. * * count = taille de la liste constituée. [OUT] * * * * Description : Fournit la liste des noeuds intégrés dans une collection. * * * -* Retour : Enfants d'un noeud issu d'une collection Yaml. * +* Retour : Enfants d'un noeud issu d'une collection YAML. * * * * Remarques : - * * * @@ -275,59 +295,63 @@ GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *collec, size_t *c /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* nodes = liste de noeuds avec correspondance établie. [OUT] * -* count = quantité de ces noeuds. [OUT] * +* Paramètres : collec = noeud d'arborescence YAML à consulter. * * * -* Description : Recherche les noeuds correspondant à un chemin. * +* Description : Fournit le premier noeud intégré dans une collection. * * * -* Retour : - * +* Retour : Noeud issu d'une collection YAML. * * * * Remarques : - * * * ******************************************************************************/ -static void g_yaml_collection_find_by_path(const GYamlCollection *collec, const char *path, bool prepare, GYamlNode ***nodes, size_t *count) +GYamlNode *g_yaml_collection_get_first_node(const GYamlCollection *collec) { - size_t i; /* Boucle de parcours */ + GYamlNode *result; /* Elément à retourner */ - if (path[0] != '/') - goto wrong_path; + if (collec->count == 0) + result = NULL; - if (path[1] == '\0') + else { - if (prepare) - { - *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **)); + result = collec->nodes[0]; + g_object_ref(G_OBJECT(result)); + } - g_object_ref(G_OBJECT(collec)); - (*nodes)[*count - 1] = G_YAML_NODE(collec); + return result; - } - else - { - *nodes = realloc(*nodes, (*count + collec->count) * sizeof(GYamlNode **)); +} - for (i = 0; i < collec->count; i++) - { - g_object_ref(G_OBJECT(collec->nodes[i])); - (*nodes)[*count + i] = collec->nodes[i]; - } - *count += collec->count; - } +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ - } - else - for (i = 0; i < collec->count; i++) - _g_yaml_node_find_by_path(collec->nodes[i], path, prepare, nodes, count); +/****************************************************************************** +* * +* Paramètres : collec = noeud d'arborescence YAML à consulter. * +* path = chemin d'accès à parcourir. * +* * +* Description : Recherche le premier noeud correspondant à un chemin. * +* * +* Retour : Noeud avec la correspondance établie ou NULL si non trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GYamlNode *g_yaml_collection_find_first_by_path(GYamlCollection *collec, const char *path) +{ + GYamlNode *result; /* Trouvaille à retourner */ + size_t i; /* Boucle de parcours */ + + result = NULL; - wrong_path: + for (i = 0; i < collec->count && result == NULL; i++) + result = g_yaml_node_find_first_by_path(collec->nodes[i], path); - ; + return result; } diff --git a/plugins/yaml/collection.h b/plugins/yaml/collection.h index 4d74d29..8a026ae 100644 --- a/plugins/yaml/collection.h +++ b/plugins/yaml/collection.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * collection.h - prototypes pour une collection de noeuds Yaml de type "sequence" ou "mapping" + * collection.h - prototypes pour une collection de noeuds YAML de type "sequence" ou "mapping" * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -41,28 +41,31 @@ #define G_YAML_COLLEC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_COLLEC, GYamlCollectionClass)) -/* Collection de noeuds au format Yaml (instance) */ +/* Collection de noeuds au format YAML (instance) */ typedef struct _GYamlCollection GYamlCollection; -/* Collection de noeuds au format Yaml (classe) */ +/* Collection de noeuds au format YAML (classe) */ typedef struct _GYamlCollectionClass GYamlCollectionClass; -/* Indique le type défini pour une collection de noeuds Yaml. */ +/* Indique le type défini pour une collection de noeuds YAML. */ GType g_yaml_collection_get_type(void); -/* Construit une collection de noeuds Yaml. */ +/* Construit une collection de noeuds YAML. */ GYamlCollection *g_yaml_collection_new(bool); -/* Indique la nature d'une collection Yaml. */ +/* Indique la nature d'une collection YAML. */ bool g_yaml_collection_is_sequence(const GYamlCollection *); -/* Ajoute un noeud à une collection de noeuds Yaml. */ +/* Ajoute un noeud à une collection de noeuds YAML. */ void g_yaml_collection_add_node(GYamlCollection *, GYamlNode *); /* Fournit la liste des noeuds intégrés dans une collection. */ GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *, size_t *); +/* Fournit le premier noeud intégré dans une collection. */ +GYamlNode *g_yaml_collection_get_first_node(const GYamlCollection *); + #endif /* PLUGINS_YAML_COLLECTION_H */ diff --git a/plugins/yaml/core.c b/plugins/yaml/core.c index ffc7edd..7dc0570 100644 --- a/plugins/yaml/core.c +++ b/plugins/yaml/core.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * core.c - lecture de contenus au format Yaml * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -27,12 +27,12 @@ #include <plugins/self.h> -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # include "python/module.h" #endif -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS # define PG_REQ RL("PyChrysalide") #else # define PG_REQ NO_REQ @@ -63,7 +63,7 @@ G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *plugin) result = true; -#ifdef HAVE_PYTHON3_BINDINGS +#ifdef INCLUDE_PYTHON3_BINDINGS if (result) result = add_yaml_module_to_python_module(); diff --git a/plugins/yaml/core.h b/plugins/yaml/core.h index a46dbe7..b846e24 100644 --- a/plugins/yaml/core.h +++ b/plugins/yaml/core.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * core.h - prototypes pour la lecture de contenus au format Yaml * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * diff --git a/plugins/yaml/line.h b/plugins/yaml/line.h deleted file mode 100644 index 00f019e..0000000 --- a/plugins/yaml/line.h +++ /dev/null @@ -1,75 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * line.h - prototypes pour une ligne de contenu Yaml - * - * Copyright (C) 2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. - */ - - -#ifndef PLUGINS_YAML_LINE_H -#define PLUGINS_YAML_LINE_H - - -#include <glib-object.h> -#include <stdbool.h> - - - -#define G_TYPE_YAML_LINE g_yaml_line_get_type() -#define G_YAML_LINE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_LINE, GYamlLine)) -#define G_IS_YAML_LINE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_LINE)) -#define G_YAML_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_LINE, GYamlLineClass)) -#define G_IS_YAML_LINE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_LINE)) -#define G_YAML_LINE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_LINE, GYamlLineClass)) - - -/* Ligne de données au format Yaml (instance) */ -typedef struct _GYamlLine GYamlLine; - -/* Ligne de données au format Yaml (classe) */ -typedef struct _GYamlLineClass GYamlLineClass; - - -/* Indique le type défini pour une ligne de données au format Yaml. */ -GType g_yaml_line_get_type(void); - -/* Met en place un gestionnaire pour ligne au format Yaml. */ -GYamlLine *g_yaml_line_new(const char *, size_t); - -/* Fournit la taille de l'indentation d'une ligne Yaml. */ -size_t g_yaml_line_count_indent(const GYamlLine *); - -/* Indique si la ligne représente un élément de liste. */ -bool g_yaml_line_is_list_item(const GYamlLine *); - -/* Fournit la charge utile associée à une ligne Yaml. */ -const char *g_yaml_line_get_payload(const GYamlLine *); - -/* Fournit la clef associée à une ligne Yaml si elle existe. */ -const char *g_yaml_line_get_key(const GYamlLine *); - -/* Fournit la valeur associée à une ligne Yaml si elle existe. */ -const char *g_yaml_line_get_value(const GYamlLine *); - - - -#define g_yaml_line_get_number(l) 0 - - - -#endif /* PLUGINS_YAML_LINE_H */ diff --git a/plugins/yaml/node-int.h b/plugins/yaml/node-int.h index a389f61..cd87950 100644 --- a/plugins/yaml/node-int.h +++ b/plugins/yaml/node-int.h @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * node-int.h - prototypes internes pour la définition d'un noeud Yaml + * node-int.h - prototypes internes pour la définition d'un noeud YAML * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -29,32 +29,26 @@ -/* Recherche les noeuds correspondant à un chemin. */ -typedef void (* find_yaml_node_fc) (const GYamlNode *, const char *, bool, GYamlNode ***, size_t *); +/* Recherche le premier noeud correspondant à un chemin. */ +typedef GYamlNode * (* find_first_yaml_node_fc) (GYamlNode *, const char *); -/* Noeud d'une arborescence au format Yaml (instance) */ +/* Noeud d'une arborescence au format YAML (instance) */ struct _GYamlNode { GObject parent; /* A laisser en premier */ - GYamlLine *line; /* Line Yaml d'origine */ - }; -/* Noeud d'une arborescence au format Yaml (classe) */ +/* Noeud d'une arborescence au format YAML (classe) */ struct _GYamlNodeClass { GObjectClass parent; /* A laisser en premier */ - find_yaml_node_fc find; /* Recherche par chemin */ + find_first_yaml_node_fc find; /* Recherche par chemin */ }; -/* Recherche les noeuds correspondant à un chemin. */ -void _g_yaml_node_find_by_path(const GYamlNode *, const char *, bool, GYamlNode ***, size_t *); - - #endif /* PLUGINS_YAML_NODE_INT_H */ diff --git a/plugins/yaml/node.c b/plugins/yaml/node.c index 7b3413d..ff6fa7e 100644 --- a/plugins/yaml/node.c +++ b/plugins/yaml/node.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * node.c - définition de noeud Yaml + * node.c - définition de noeud YAML * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -24,17 +24,14 @@ #include "node.h" -#include <string.h> - - #include "node-int.h" -/* Initialise la classe des noeuds d'arborescence Yaml. */ +/* Initialise la classe des noeuds d'arborescence YAML. */ static void g_yaml_node_class_init(GYamlNodeClass *); -/* Initialise une instance de noeud d'arborescence Yaml. */ +/* Initialise une instance de noeud d'arborescence YAML. */ static void g_yaml_node_init(GYamlNode *); /* Supprime toutes les références externes. */ @@ -45,7 +42,7 @@ static void g_yaml_node_finalize(GYamlNode *); -/* Indique le type défini pour un noeud d'arborescence Yaml. */ +/* Indique le type défini pour un noeud d'arborescence YAML. */ G_DEFINE_TYPE(GYamlNode, g_yaml_node, G_TYPE_OBJECT); @@ -53,7 +50,7 @@ G_DEFINE_TYPE(GYamlNode, g_yaml_node, G_TYPE_OBJECT); * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des noeuds d'arborescence Yaml. * +* Description : Initialise la classe des noeuds d'arborescence YAML. * * * * Retour : - * * * @@ -77,7 +74,7 @@ static void g_yaml_node_class_init(GYamlNodeClass *klass) * * * Paramètres : node = instance à initialiser. * * * -* Description : Initialise une instance de noeud d'arborescence Yaml. * +* Description : Initialise une instance de noeud d'arborescence YAML. * * * * Retour : - * * * @@ -87,7 +84,6 @@ static void g_yaml_node_class_init(GYamlNodeClass *klass) static void g_yaml_node_init(GYamlNode *node) { - node->line = NULL; } @@ -106,8 +102,6 @@ static void g_yaml_node_init(GYamlNode *node) static void g_yaml_node_dispose(GYamlNode *node) { - g_clear_object(&node->line); - G_OBJECT_CLASS(g_yaml_node_parent_class)->dispose(G_OBJECT(node)); } @@ -134,119 +128,37 @@ static void g_yaml_node_finalize(GYamlNode *node) /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* Paramètres : node = noeud d'arborescence YAML à consulter. * +* path = chemin d'accès à parcourir. * * * -* Description : Fournit la ligne d'origine associée à un noeud. * +* Description : Recherche le premier noeud correspondant à un chemin. * * * -* Retour : Ligne Yaml à l'origine du noeud. * +* Retour : Noeud avec la correspondance établie ou NULL si non trouvé. * * * * Remarques : - * * * ******************************************************************************/ -GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node) -{ - GYamlLine *result; /* Ligne d'origine à renvoyer */ - - result = node->line; - - if (result != NULL) - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* nodes = liste de noeuds avec correspondance établie. [OUT] * -* count = quantité de ces noeuds. [OUT] * -* * -* Description : Recherche les noeuds correspondant à un chemin. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void _g_yaml_node_find_by_path(const GYamlNode *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count) +GYamlNode *g_yaml_node_find_first_by_path(GYamlNode *node, const char *path) { + GYamlNode *result; /* Trouvaille à retourner */ GYamlNodeClass *class; /* Classe de l'instance */ - class = G_YAML_NODE_GET_CLASS(node); - - class->find(node, path, prepare, nodes, count); - -} + while (path[0] == '/') + path++; - -/****************************************************************************** -* * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* nodes = liste de noeuds avec correspondance établie. [OUT] * -* count = quantité de ces noeuds. [OUT] * -* * -* Description : Recherche les noeuds correspondant à un chemin. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_yaml_node_find_by_path(const GYamlNode *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count) -{ - *nodes = NULL; - *count = 0; - - _g_yaml_node_find_by_path(node, path, prepare, nodes, count); - -} - - -/****************************************************************************** -* * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* * -* Description : Recherche l'unique noeud correspondant à un chemin. * -* * -* Retour : Noeud avec correspondance établie ou NULL. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GYamlNode *g_yaml_node_find_one_by_path(const GYamlNode *node, const char *path, bool prepare) -{ - GYamlNode *result; /* Trouvaille unique à renvoyer*/ - GYamlNode **nodes; /* Liste de noeuds trouvés */ - size_t count; /* Taille de cette liste */ - size_t i; /* Boucle de parcours */ - - g_yaml_node_find_by_path(node, path, prepare, &nodes, &count); - - if (count == 1) + if (path[0] == '\0') { - result = nodes[0]; + result = node; g_object_ref(G_OBJECT(result)); } else - result = NULL; + { + class = G_YAML_NODE_GET_CLASS(node); - for (i = 0; i < count; i++) - g_object_unref(G_OBJECT(nodes[i])); + result = class->find(node, path); - if (nodes != NULL) - free(nodes); + } return result; diff --git a/plugins/yaml/node.h b/plugins/yaml/node.h index 8197ef5..36c8e7b 100644 --- a/plugins/yaml/node.h +++ b/plugins/yaml/node.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * node.h - prototypes pour une définition de noeud Yaml * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -26,15 +26,8 @@ #include <glib-object.h> -#include <stdbool.h> -#include "line.h" - - -/* Depuis collection.h : collection de noeuds au format Yaml (instance) */ -typedef struct _GYamlCollection GYamlCollection; - #define G_TYPE_YAML_NODE g_yaml_node_get_type() #define G_YAML_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_NODE, GYamlNode)) @@ -44,24 +37,18 @@ typedef struct _GYamlCollection GYamlCollection; #define G_YAML_NODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_NODE, GYamlNodeClass)) -/* Noeud d'une arborescence au format Yaml (instance) */ +/* Noeud d'une arborescence au format YAML (instance) */ typedef struct _GYamlNode GYamlNode; -/* Noeud d'une arborescence au format Yaml (classe) */ +/* Noeud d'une arborescence au format YAML (classe) */ typedef struct _GYamlNodeClass GYamlNodeClass; /* Indique le type défini pour un noeud d'arborescence Yaml. */ GType g_yaml_node_get_type(void); -/* Fournit la ligne d'origine associée à un noeud. */ -GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *); - -/* Recherche les noeuds correspondant à un chemin. */ -void g_yaml_node_find_by_path(const GYamlNode *, const char *, bool, GYamlNode ***, size_t *); - -/* Recherche l'unique noeud correspondant à un chemin. */ -GYamlNode *g_yaml_node_find_one_by_path(const GYamlNode *, const char *, bool); +/* Recherche le premier noeud correspondant à un chemin. */ +GYamlNode *g_yaml_node_find_first_by_path(GYamlNode *, const char *); diff --git a/plugins/yaml/pair-int.h b/plugins/yaml/pair-int.h new file mode 100644 index 0000000..88b968d --- /dev/null +++ b/plugins/yaml/pair-int.h @@ -0,0 +1,66 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * pair-int.h - prototypes internes pour la définition d'un noeud YAML + * + * Copyright (C) 2020-2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_YAML_PAIR_INT_H +#define PLUGINS_YAML_PAIR_INT_H + + +#include "pair.h" + + +#include <stdbool.h> + + +#include "node-int.h" + + + +/* Noeud d'une arborescence au format YAML (instance) */ +struct _GYamlPair +{ + GYamlNode parent; /* A laisser en premier */ + + char *key; /* Clef présente dans le noeud */ + YamlOriginalStyle key_style; /* Forme d'origine associé */ + + char *value; /* Valeur associée */ + YamlOriginalStyle value_style; /* Forme d'origine associé */ + + GYamlCollection *children; /* Collection de noeuds */ + +}; + +/* Noeud d'une arborescence au format YAML (classe) */ +struct _GYamlPairClass +{ + GYamlNodeClass parent; /* A laisser en premier */ + +}; + + +/* Met en place une pair clef/valeur YAML. */ +bool g_yaml_pair_create(GYamlPair *, const char *, YamlOriginalStyle, const char *, YamlOriginalStyle); + + + +#endif /* PLUGINS_YAML_PAIR_INT_H */ diff --git a/plugins/yaml/pair.c b/plugins/yaml/pair.c index 0e96937..4faba88 100644 --- a/plugins/yaml/pair.c +++ b/plugins/yaml/pair.c @@ -1,8 +1,8 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * pair.c - noeud Yaml de paire clef/valeur + * pair.c - noeud YAML de paire clef/valeur * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -24,38 +24,25 @@ #include "pair.h" +#include <assert.h> #include <malloc.h> #include <string.h> -#include "node-int.h" +#include <common/extstr.h> +#include "pair-int.h" -/* Noeud d'une arborescence au format Yaml (instance) */ -struct _GYamlPair -{ - GYamlNode parent; /* A laisser en premier */ - - char *key; /* Clef présente dans le noeud */ - char *value; /* Valeur associée */ - - GYamlCollection *collection; /* Collection de noeuds */ -}; - -/* Noeud d'une arborescence au format Yaml (classe) */ -struct _GYamlPairClass -{ - GYamlNodeClass parent; /* A laisser en premier */ -}; +/* -------------------- DEFINITIONS PROPRES POUR LE SUPPORT YAML -------------------- */ -/* Initialise la classe des noeuds d'arborescence Yaml. */ +/* Initialise la classe des noeuds d'arborescence YAML. */ static void g_yaml_pair_class_init(GYamlPairClass *); -/* Initialise une instance de noeud d'arborescence Yaml. */ +/* Initialise une instance de noeud d'arborescence YAML. */ static void g_yaml_pair_init(GYamlPair *); /* Supprime toutes les références externes. */ @@ -64,12 +51,22 @@ static void g_yaml_pair_dispose(GYamlPair *); /* Procède à la libération totale de la mémoire. */ static void g_yaml_pair_finalize(GYamlPair *); -/* Recherche les noeuds correspondant à un chemin. */ -static void g_yaml_pair_find_by_path(const GYamlPair *, const char *, bool, GYamlNode ***, size_t *); +/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ + + +/* Recherche le premier noeud correspondant à un chemin. */ +static GYamlNode *g_yaml_pair_find_first_by_path(GYamlPair *, const char *); + + + +/* ---------------------------------------------------------------------------------- */ +/* DEFINITIONS PROPRES POUR LE SUPPORT YAML */ +/* ---------------------------------------------------------------------------------- */ -/* Indique le type défini pour un noeud d'arborescence Yaml. */ + +/* Indique le type défini pour un noeud d'arborescence YAML. */ G_DEFINE_TYPE(GYamlPair, g_yaml_pair, G_TYPE_YAML_NODE); @@ -77,7 +74,7 @@ G_DEFINE_TYPE(GYamlPair, g_yaml_pair, G_TYPE_YAML_NODE); * * * Paramètres : klass = classe à initialiser. * * * -* Description : Initialise la classe des noeuds d'arborescence Yaml. * +* Description : Initialise la classe des noeuds d'arborescence YAML. * * * * Retour : - * * * @@ -97,16 +94,16 @@ static void g_yaml_pair_class_init(GYamlPairClass *klass) node = G_YAML_NODE_CLASS(klass); - node->find = (find_yaml_node_fc)g_yaml_pair_find_by_path; + node->find = (find_first_yaml_node_fc)g_yaml_pair_find_first_by_path; } /****************************************************************************** * * -* Paramètres : node = instance à initialiser. * +* Paramètres : pair = instance à initialiser. * * * -* Description : Initialise une instance de noeud d'arborescence Yaml. * +* Description : Initialise une instance de noeud d'arborescence YAML. * * * * Retour : - * * * @@ -114,19 +111,22 @@ static void g_yaml_pair_class_init(GYamlPairClass *klass) * * ******************************************************************************/ -static void g_yaml_pair_init(GYamlPair *node) +static void g_yaml_pair_init(GYamlPair *pair) { - node->key = NULL; - node->value = NULL; + pair->key = NULL; + pair->key_style = YOS_PLAIN; + + pair->value = NULL; + pair->value_style = YOS_PLAIN; - node->collection = NULL; + pair->children = NULL; } /****************************************************************************** * * -* Paramètres : node = instance d'objet GLib à traiter. * +* Paramètres : pair = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * @@ -136,18 +136,18 @@ static void g_yaml_pair_init(GYamlPair *node) * * ******************************************************************************/ -static void g_yaml_pair_dispose(GYamlPair *node) +static void g_yaml_pair_dispose(GYamlPair *pair) { - g_clear_object(&node->collection); + g_clear_object(&pair->children); - G_OBJECT_CLASS(g_yaml_pair_parent_class)->dispose(G_OBJECT(node)); + G_OBJECT_CLASS(g_yaml_pair_parent_class)->dispose(G_OBJECT(pair)); } /****************************************************************************** * * -* Paramètres : node = instance d'objet GLib à traiter. * +* Paramètres : pair = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * @@ -157,24 +157,27 @@ static void g_yaml_pair_dispose(GYamlPair *node) * * ******************************************************************************/ -static void g_yaml_pair_finalize(GYamlPair *node) +static void g_yaml_pair_finalize(GYamlPair *pair) { - if (node->key != NULL) - free(node->key); + if (pair->key != NULL) + free(pair->key); - if (node->value != NULL) - free(node->value); + if (pair->value != NULL) + free(pair->value); - G_OBJECT_CLASS(g_yaml_pair_parent_class)->finalize(G_OBJECT(node)); + G_OBJECT_CLASS(g_yaml_pair_parent_class)->finalize(G_OBJECT(pair)); } /****************************************************************************** * * -* Paramètres : line = ligne Yaml à l'origine du futur noeud. * +* Paramètres : key = désignation pour le noeud YAML. * +* kstyle = format d'origine de la clef. * +* value = éventuelle valeur directe portée par le noeud. * +* vstyle = éventuel format d'origine de l'éventuelle valeur. * * * -* Description : Construit un noeud d'arborescence Yaml. * +* Description : Construit un noeud d'arborescence YAML. * * * * Retour : Instance mise en place ou NULL en cas d'échec. * * * @@ -182,33 +185,14 @@ static void g_yaml_pair_finalize(GYamlPair *node) * * ******************************************************************************/ -GYamlPair *g_yaml_pair_new(GYamlLine *line) +GYamlPair *g_yaml_pair_new(const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle) { GYamlPair *result; /* Structure à retourner */ - const char *key; /* Clef associée au noeud */ - const char *value; /* Eventuelle valeur associée */ - - key = g_yaml_line_get_key(line); - value = g_yaml_line_get_value(line); - - if (key == NULL) - result = NULL; - else - { - result = g_object_new(G_TYPE_YAML_PAIR, NULL); - - G_YAML_NODE(result)->line = line; - g_object_ref(G_OBJECT(line)); + result = g_object_new(G_TYPE_YAML_PAIR, NULL); - result->key = strdup(key); - - if (value == NULL) - result->value = NULL; - else - result->value = strdup(value); - - } + if (!g_yaml_pair_create(result, key, kstyle, value, vstyle)) + g_clear_object(&result); return result; @@ -217,105 +201,126 @@ GYamlPair *g_yaml_pair_new(GYamlLine *line) /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* nodes = liste de noeuds avec correspondance établie. [OUT] * -* count = quantité de ces noeuds. [OUT] * +* Paramètres : pair = paire YAML à initialiser pleinement. * +* key = désignation pour le noeud YAML. * +* kstyle = format d'origine de la clef. * +* value = éventuelle valeur directe portée par le noeud. * +* vstyle = éventuel format d'origine de l'éventuelle valeur. * * * -* Description : Recherche les noeuds correspondant à un chemin. * +* Description : Met en place une pair clef/valeur YAML. * * * -* Retour : - * +* Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ -static void g_yaml_pair_find_by_path(const GYamlPair *node, const char *path, bool prepare, GYamlNode ***nodes, size_t *count) +bool g_yaml_pair_create(GYamlPair *pair, const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle) { - char *next; /* Prochaine partie du chemin */ - size_t cmplen; /* Etendue de la comparaison */ - int ret; /* Bilan d'une comparaison */ + bool result; /* Bilan à retourner */ - if (path[0] == '\0') - goto exit; + result = true; - /* Correspondance au niveau du noeud ? */ + pair->key = strdup(key); + pair->key_style = kstyle; - if (path[0] == '/') + if (value != NULL) { - path++; + pair->value = strdup(value); + pair->value_style = vstyle; + } - if (path[0] == '\0') - goto matched; + return result; - } +} - next = strchr(path, '/'); - if (next == NULL) - ret = strcmp(path, node->key); +/****************************************************************************** +* * +* Paramètres : pair = noeud d'arborescence YAML à consulter. * +* * +* Description : Fournit la clef représentée dans une paire en YAML. * +* * +* Retour : Clef sous forme de chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ - else - { - cmplen = next - path; +const char *g_yaml_pair_get_key(const GYamlPair *pair) +{ + char *result; /* Valeur à retourner */ - if (cmplen == 0) - goto cont; + result = pair->key; - ret = strncmp(path, node->key, cmplen); + return result; - } +} - if (ret != 0) - goto done; - else if (next != NULL) - { - path += cmplen; - goto cont; - } +/****************************************************************************** +* * +* Paramètres : pair = noeud d'arborescence YAML à consulter. * +* * +* Description : Indique le format d'origine YAML associé à la clef. * +* * +* Retour : Valeur renseignée lors du chargement du noeud. * +* * +* Remarques : - * +* * +******************************************************************************/ - matched: +YamlOriginalStyle g_yaml_pair_get_key_style(const GYamlPair *pair) +{ + YamlOriginalStyle result; /* Indication à retourner */ - *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **)); + result = pair->key_style; - g_object_ref(G_OBJECT(node)); - (*nodes)[*count - 1] = G_YAML_NODE(node); + return result; - goto done; +} - cont: - if (node->collection != NULL) - _g_yaml_node_find_by_path(G_YAML_NODE(node->collection), path, prepare, nodes, count); +/****************************************************************************** +* * +* Paramètres : pair = noeud d'arborescence YAML à consulter. * +* * +* Description : Fournit l'éventuelle valeur d'une paire en YAML. * +* * +* Retour : Valeur sous forme de chaîne de caractères ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ - done: +const char *g_yaml_pair_get_value(const GYamlPair *pair) +{ + char *result; /* Valeur à retourner */ - exit: + result = pair->value; - ; + return result; } /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* Paramètres : pair = noeud d'arborescence YAML à consulter. * * * -* Description : Fournit la clef représentée dans une paire en Yaml. * +* Description : Indique le format d'origine YAML associé à la valeur. * * * -* Retour : Clef sous forme de chaîne de caractères. * +* Retour : Valeur renseignée lors du chargement du noeud. * * * * Remarques : - * * * ******************************************************************************/ -const char *g_yaml_pair_get_key(const GYamlPair *node) +YamlOriginalStyle g_yaml_pair_get_value_style(const GYamlPair *pair) { - char *result; /* Valeur à retourner */ + YamlOriginalStyle result; /* Indication à retourner */ - result = node->key; + result = pair->value_style; return result; @@ -324,9 +329,9 @@ const char *g_yaml_pair_get_key(const GYamlPair *node) /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* Paramètres : pair = noeud d'arborescence YAML à consulter. * * * -* Description : Fournit l'éventuelle valeur d'une paire en Yaml. * +* Description : Rassemble une éventuelle séquence de valeurs attachées. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * @@ -334,11 +339,88 @@ const char *g_yaml_pair_get_key(const GYamlPair *node) * * ******************************************************************************/ -const char *g_yaml_pair_get_value(const GYamlPair *node) +char *g_yaml_pair_aggregate_value(const GYamlPair *pair) { char *result; /* Valeur à retourner */ + GYamlNode **nodes; /* Eventuels noeuds trouvés */ + size_t count; /* Quantité de ces noeuds */ + size_t i; /* Boucle de parcours */ + GYamlPair *child; /* Couple clef/valeur enfant */ + bool failed; /* Détection d'un échec */ + + result = NULL; + + if (pair->value != NULL) + result = strdup(pair->value); + + else if (pair->children != NULL) + { + if (!g_yaml_collection_is_sequence(pair->children)) + goto exit; + + nodes = g_yaml_collection_get_nodes(pair->children, &count); + + if (count == 0) + result = strdup("[ ]"); + + else + { + result = strdup("[ "); + + for (i = 0; i < count; i++) + { + if (!G_IS_YAML_PAIR(nodes[i])) + break; + + child = G_YAML_PAIR(nodes[i]); + + if (child->value != NULL) + break; + + if (i > 0) + result = stradd(result, ", "); + + switch (child->key_style) + { + case YOS_PLAIN: + result = stradd(result, child->key); + break; + + case YOS_SINGLE_QUOTED: + result = straddfmt(result, "'%s'", child->key); + break; + + case YOS_DOUBLE_QUOTED: + result = straddfmt(result, "\"%s\"", child->key); + break; + + } + + g_object_unref(G_OBJECT(nodes[i])); + + } - result = node->value; + failed = (i < count); + + for (; i < count; i++) + g_object_unref(G_OBJECT(nodes[i])); + + free(nodes); + + if (failed) + { + free(result); + result = NULL; + } + + else + result = stradd(result, " ]"); + + } + + } + + exit: return result; @@ -347,10 +429,10 @@ const char *g_yaml_pair_get_value(const GYamlPair *node) /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à compléter. * -* collec = collection de noeuds Yaml. * +* Paramètres : pair = noeud d'arborescence YAML à compléter. * +* children = collection de noeuds YAML. * * * -* Description : Attache une collection de noeuds Yaml à un noeud. * +* Description : Attache une collection de noeuds YAML à un noeud. * * * * Retour : - * * * @@ -358,33 +440,33 @@ const char *g_yaml_pair_get_value(const GYamlPair *node) * * ******************************************************************************/ -void g_yaml_pair_set_collection(GYamlPair *node, GYamlCollection *collec) +void g_yaml_pair_set_children(GYamlPair *pair, GYamlCollection *children) { - g_clear_object(&node->collection); + g_clear_object(&pair->children); - g_object_ref_sink(G_OBJECT(collec)); - node->collection = collec; + g_object_ref_sink(G_OBJECT(children)); + pair->children = children; } /****************************************************************************** * * -* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* Paramètres : pair = noeud d'arborescence YAML à consulter. * * * * Description : Fournit une éventuelle collection rattachée à un noeud. * * * -* Retour : Collection de noeuds Yaml ou NULL. * +* Retour : Collection de noeuds YAML ou NULL. * * * * Remarques : - * * * ******************************************************************************/ -GYamlCollection *g_yaml_pair_get_collection(const GYamlPair *node) +GYamlCollection *g_yaml_pair_get_children(const GYamlPair *pair) { GYamlCollection *result; /* Collection à renvoyer */ - result = node->collection; + result = pair->children; if (result != NULL) g_object_ref(G_OBJECT(result)); @@ -392,3 +474,76 @@ GYamlCollection *g_yaml_pair_get_collection(const GYamlPair *node) return result; } + + + +/* ---------------------------------------------------------------------------------- */ +/* IMPLEMENTATION DES FONCTIONS DE CLASSE */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : pair = noeud d'arborescence YAML à consulter. * +* path = chemin d'accès à parcourir. * +* * +* Description : Recherche le premier noeud correspondant à un chemin. * +* * +* Retour : Noeud avec la correspondance établie ou NULL si non trouvé. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GYamlNode *g_yaml_pair_find_first_by_path(GYamlPair *pair, const char *path) +{ + GYamlNode *result; /* Trouvaille à retourner */ + char *next; /* Prochaine partie du chemin */ + size_t cmplen; /* Etendue de la comparaison */ + int ret; /* Bilan d'une comparaison */ + + assert(path[0] != '/' && path[0] != '\0'); + + /* Correspondance au niveau du noeud ? */ + + next = strchr(path, '/'); + + if (next == NULL) + ret = strcmp(path, pair->key); + + else + { + cmplen = next - path; + assert(cmplen > 0); + + ret = strncmp(path, pair->key, cmplen); + + } + + /* Si correspondance il y a... */ + + if (ret == 0) + { + /* ... et que la recherche se trouve en bout de parcours */ + if (next == NULL) + { + result = G_YAML_NODE(pair); + g_object_ref(G_OBJECT(result)); + } + + /* Recherche supplémentaire dans les sous-noeuds ? */ + + else if (pair->children != NULL) + result = g_yaml_node_find_first_by_path(G_YAML_NODE(pair->children), path + cmplen); + + else + result = NULL; + + } + + else + result = NULL; + + return result; + +} diff --git a/plugins/yaml/pair.h b/plugins/yaml/pair.h index 986fef7..5265392 100644 --- a/plugins/yaml/pair.h +++ b/plugins/yaml/pair.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * pair.h - prototypes pour un noeud Yaml de paire clef/valeur * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -30,7 +30,6 @@ #include "collection.h" -#include "line.h" #include "node.h" @@ -49,23 +48,42 @@ typedef struct _GYamlPair GYamlPair; typedef struct _GYamlPairClass GYamlPairClass; +/* Format d'origine des éléments du couple clef/valeur */ +typedef enum _YamlOriginalStyle +{ + YOS_PLAIN, /* Mode brut, par défaut */ + YOS_SINGLE_QUOTED, /* Encadré simplement */ + YOS_DOUBLE_QUOTED, /* ENcadré avec des guillemets */ + +} YamlOriginalStyle; + + /* Indique le type défini pour un noeud d'arborescence Yaml. */ GType g_yaml_pair_get_type(void); /* Construit un noeud d'arborescence Yaml. */ -GYamlPair *g_yaml_pair_new(GYamlLine *); +GYamlPair *g_yaml_pair_new(const char *, YamlOriginalStyle, const char *, YamlOriginalStyle); /* Fournit la clef représentée dans une paire en Yaml. */ const char *g_yaml_pair_get_key(const GYamlPair *); +/* Indique le format d'origine YAML associé à la clef. */ +YamlOriginalStyle g_yaml_pair_get_key_style(const GYamlPair *); + /* Fournit l'éventuelle valeur d'une paire en Yaml. */ const char *g_yaml_pair_get_value(const GYamlPair *); +/* Indique le format d'origine YAML associé à la valeur. */ +YamlOriginalStyle g_yaml_pair_get_value_style(const GYamlPair *); + +/* Rassemble une éventuelle séquence de valeurs attachées. */ +char *g_yaml_pair_aggregate_value(const GYamlPair *); + /* Attache une collection de noeuds Yaml à un noeud. */ -void g_yaml_pair_set_collection(GYamlPair *, GYamlCollection *); +void g_yaml_pair_set_children(GYamlPair *, GYamlCollection *); /* Fournit une éventuelle collection rattachée à un noeud. */ -GYamlCollection *g_yaml_pair_get_collection(const GYamlPair *); +GYamlCollection *g_yaml_pair_get_children(const GYamlPair *); diff --git a/plugins/yaml/parser.c b/plugins/yaml/parser.c new file mode 100644 index 0000000..8c06723 --- /dev/null +++ b/plugins/yaml/parser.c @@ -0,0 +1,299 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.c - lecteur de contenu Yaml + * + * Copyright (C) 2019-2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#include "parser.h" + + +#include <assert.h> +#include <malloc.h> +#include <yaml.h> +#include <gio/gio.h> + + +#include <analysis/contents/file.h> + + +#include "collection.h" +#include "pair.h" + + +#define SCALAR_STYLE_TO_ORIGINAL_STYLE(v) \ + ({ \ + YamlOriginalStyle __result; \ + if (v == YAML_SINGLE_QUOTED_SCALAR_STYLE) \ + __result = YOS_SINGLE_QUOTED; \ + else if (v == YAML_DOUBLE_QUOTED_SCALAR_STYLE) \ + __result = YOS_DOUBLE_QUOTED; \ + else \ + __result = YOS_PLAIN; \ + __result; \ + }) + + +/* Construit la version GLib d'un noeud YAML brut. */ +static GYamlPair *build_pair_from_yaml(yaml_document_t *, int, int); + +/* Transforme un noeud YAML brut en sa version Glib. */ +static GYamlNode *translate_yaml_node(yaml_document_t *, yaml_node_t *); + + + +/****************************************************************************** +* * +* Paramètres : document = gestionnaire de l'ensemble des noeuds bruts. * +* key = indice de la clef du noeud à convertir. * +* value = indice de la valeur du noeud à convertir. * +* * +* Description : Construit la version GLib d'un noeud YAML brut. * +* * +* Retour : Noeud GLib obtenu ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GYamlPair *build_pair_from_yaml(yaml_document_t *document, int key, int value) +{ + GYamlPair *result; /* Racine à retourner */ + yaml_node_t *key_node; /* Noeud brut de la clef */ + yaml_node_t *value_node; /* Noeud brut de la valeur */ + GYamlNode *children; /* Collection de noeuds YAML */ + + result = NULL; + + key_node = yaml_document_get_node(document, key); + assert(key_node != NULL); + + if (key_node->type != YAML_SCALAR_NODE) + goto exit; + + value_node = yaml_document_get_node(document, value); + assert(value_node != NULL); + + if (value_node->type == YAML_SCALAR_NODE) + result = g_yaml_pair_new((char *)key_node->data.scalar.value, + SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style), + (char *)value_node->data.scalar.value, + SCALAR_STYLE_TO_ORIGINAL_STYLE(value_node->data.scalar.style)); + + else + { + children = translate_yaml_node(document, value_node); + + if (children != NULL) + { + result = g_yaml_pair_new((char *)key_node->data.scalar.value, + SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style), + NULL, YOS_PLAIN); + + g_yaml_pair_set_children(result, G_YAML_COLLEC(children)); + + } + + } + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : document = gestionnaire de l'ensemble des noeuds bruts. * +* node = point de départ des transformations. * +* * +* Description : Transforme un noeud YAML brut en sa version Glib. * +* * +* Retour : Noeud GLib obtenu ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GYamlNode *translate_yaml_node(yaml_document_t *document, yaml_node_t *node) +{ + GYamlNode *result; /* Racine à retourner */ + yaml_node_item_t *index; /* Elément d'une série */ + yaml_node_t *item; /* Elément d'une série */ + GYamlNode *child; /* Version GLib de l'élément */ + yaml_node_pair_t *pair; /* Combinaison clef/valeur */ + GYamlPair *sub; /* Sous-noeud à intégrer */ + + switch (node->type) + { + case YAML_SCALAR_NODE: + result = G_YAML_NODE(g_yaml_pair_new((char *)node->data.scalar.value, + SCALAR_STYLE_TO_ORIGINAL_STYLE(node->data.scalar.style), + NULL, YOS_PLAIN)); + break; + + case YAML_SEQUENCE_NODE: + + result = G_YAML_NODE(g_yaml_collection_new(true)); + + for (index = node->data.sequence.items.start; index < node->data.sequence.items.top; index++) + { + item = yaml_document_get_node(document, *index); + assert(item != NULL); + + child = translate_yaml_node(document, item); + + if (child == NULL) + { + g_clear_object(&result); + break; + } + + g_yaml_collection_add_node(G_YAML_COLLEC(result), child); + + } + + break; + + case YAML_MAPPING_NODE: + + result = G_YAML_NODE(g_yaml_collection_new(false)); + + for (pair = node->data.mapping.pairs.start; pair < node->data.mapping.pairs.top; pair++) + { + sub = build_pair_from_yaml(document, pair->key, pair->value); + + if (sub == NULL) + { + g_clear_object(&result); + break; + } + + g_yaml_collection_add_node(G_YAML_COLLEC(result), G_YAML_NODE(sub)); + + } + + break; + + default: + assert(false); + result = NULL; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : text = définitions textuelles d'un contenu brut. * +* len = taille de ces définitions. * +* * +* Description : Crée une arborescence YAML pour contenu au format adapté. * +* * +* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlNode *parse_yaml_from_text(const char *text, size_t len) +{ + GYamlNode *result; /* Racine à retourner */ + yaml_parser_t parser; /* Lecteur du contenu fourni */ + yaml_document_t document; /* Document YAML constitué */ + int ret; /* Bilan de la constitution */ + yaml_node_t *root; /* Elément racine brut */ + + result = NULL; + + yaml_parser_initialize(&parser); + + yaml_parser_set_input_string(&parser, (const unsigned char *)text, len); + + ret = yaml_parser_load(&parser, &document); + if (ret != 1) goto bad_loading; + + root = yaml_document_get_root_node(&document); + + if (root != NULL) + result = translate_yaml_node(&document, root); + + yaml_document_delete(&document); + + bad_loading: + + yaml_parser_delete(&parser); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : filename = chemin vers des définitions de règles. * +* * +* Description : Crée une arborescence YAML pour fichier au format adapté. * +* * +* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlNode *parse_yaml_from_file(const char *filename) +{ + GYamlNode *result; /* Racine à retourner */ + GBinContent *content; /* Fichier à parcourir */ + phys_t size; /* Taille du contenu associé */ + vmpa2t start; /* Tête de lecture */ + const bin_t *data; /* Données à consulter */ + char *dumped; /* Contenu manipulable */ + + result = NULL; + + content = g_file_content_new(filename); + if (content == NULL) goto no_content; + + size = g_binary_content_compute_size(content); + + g_binary_content_compute_start_pos(content, &start); + data = g_binary_content_get_raw_access(content, &start, size); + + dumped = malloc((size + 1) * sizeof(char)); + + memcpy(dumped, data, size); + dumped[size] = '\0'; + + result = parse_yaml_from_text(dumped, size); + + free(dumped); + + g_object_unref(G_OBJECT(content)); + + no_content: + + return result; + +} diff --git a/plugins/yaml/parser.h b/plugins/yaml/parser.h new file mode 100644 index 0000000..761e12b --- /dev/null +++ b/plugins/yaml/parser.h @@ -0,0 +1,43 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.h - prototypes pour le lecteur de contenu Yaml + * + * Copyright (C) 2019-2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. + */ + + +#ifndef PLUGINS_YAML_PARSER_H +#define PLUGINS_YAML_PARSER_H + + +#include <sys/types.h> + + +#include "node.h" + + + +/* Crée une arborescence YAML pour contenu au format adapté. */ +GYamlNode *parse_yaml_from_text(const char *, size_t); + +/* Crée une arborescence YAML pour fichier au format adapté. */ +GYamlNode *parse_yaml_from_file(const char *); + + + +#endif /* PLUGINS_YAML_PARSER_H */ diff --git a/plugins/yaml/python/Makefile.am b/plugins/yaml/python/Makefile.am index 4662a8e..f3dc989 100644 --- a/plugins/yaml/python/Makefile.am +++ b/plugins/yaml/python/Makefile.am @@ -3,23 +3,16 @@ noinst_LTLIBRARIES = libyamlpython.la libyamlpython_la_SOURCES = \ collection.h collection.c \ - line.h line.c \ + constants.h constants.c \ module.h module.c \ node.h node.c \ pair.h pair.c \ - reader.h reader.c \ - scalar.h scalar.c \ - tree.h tree.c + parser.h parser.c -libyamlpython_la_LDFLAGS = +libyamlpython_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ + -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT devdir = $(includedir)/chrysalide/$(subdir) dev_HEADERS = $(libyamlpython_la_SOURCES:%c=) - - -AM_CPPFLAGS = $(LIBGTK_CFLAGS) $(LIBXML_CFLAGS) $(LIBPYTHON_CFLAGS) $(LIBPYGOBJECT_CFLAGS) \ - -I$(top_srcdir)/src -DNO_IMPORT_PYGOBJECT - -AM_CFLAGS = $(DEBUG_CFLAGS) $(WARNING_FLAGS) $(COMPLIANCE_FLAGS) diff --git a/plugins/yaml/python/collection.c b/plugins/yaml/python/collection.c index e21bb9e..fd8e08a 100644 --- a/plugins/yaml/python/collection.c +++ b/plugins/yaml/python/collection.c @@ -28,18 +28,22 @@ #include <pygobject.h> +#include <i18n.h> +#include <plugins/pychrysalide/access.h> #include <plugins/pychrysalide/helpers.h> #include "node.h" -#include "../collection.h" +#include "../collection-int.h" -/* Crée un nouvel objet Python de type 'YamlCollection'. */ -static PyObject *py_yaml_collection_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(yaml_collection, G_TYPE_YAML_COLLEC); -/* Indique la nature d'une collection Yaml. */ +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_yaml_collection_init(PyObject *, PyObject *, PyObject *); + +/* Indique la nature d'une collection YAML. */ static PyObject *py_yaml_collection_is_sequence(PyObject *, void *); /* Fournit la liste des noeuds intégrés dans une collection. */ @@ -49,44 +53,56 @@ static PyObject *py_yaml_collection_get_nodes(PyObject *, void *); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'YamlCollection'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_collection_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_yaml_collection_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ int seq; /* Indicateur de type */ int ret; /* Bilan de lecture des args. */ GYamlCollection *collec; /* Création GLib à transmettre */ #define YAML_COLLECTION_DOC \ - "YamlCollection handles a collection of Yaml nodes.\n" \ + "YamlCollection handles a collection of YAML nodes.\n" \ "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ " YamlCollection(seq=False)\n" \ "\n" \ - "Where seq defines if the collection will be a sequence or a mapping of nodes." + "Where *seq* is a boolean value which defines if the collection will be a" \ + " sequence or a mapping of nodes." + + /* Récupération des paramètres */ ret = PyArg_ParseTuple(args, "p", &seq); - if (!ret) return NULL; + if (!ret) return -1; - collec = g_yaml_collection_new(seq); + /* Initialisation d'un objet GLib */ - g_object_ref_sink(G_OBJECT(collec)); - result = pygobject_new(G_OBJECT(collec)); - g_object_unref(collec); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - return result; + /* Eléments de base */ + + collec = G_YAML_COLLEC(pygobject_get(self)); + + if (!g_yaml_collection_create(collec, seq)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create YAML collection.")); + return -1; + + } + + return 0; } @@ -98,7 +114,7 @@ static PyObject *py_yaml_collection_new(PyTypeObject *type, PyObject *args, PyOb * * * Description : Fournit la liste des noeuds intégrés dans une collection. * * * -* Retour : Enfants d'un noeud issu d'une collection Yaml. * +* Retour : Enfants d'un noeud issu d'une collection YAML. * * * * Remarques : - * * * @@ -152,7 +168,7 @@ static PyObject *py_yaml_collection_get_nodes(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Indique la nature d'une collection Yaml. * +* Description : Indique la nature d'une collection YAML. * * * * Retour : Nature de la collection. * * * @@ -169,7 +185,7 @@ static PyObject *py_yaml_collection_is_sequence(PyObject *self, void *closure) #define YAML_COLLECTION_IS_SEQUENCE_ATTRIB PYTHON_IS_DEF_FULL \ ( \ sequence, py_yaml_collection, \ - "Nature of the collection: True is the collection is a sequence," \ + "Nature of the collection: True if the collection is a sequence," \ " False if it is a mapping of \"key: value\" nodes." \ ) @@ -222,7 +238,9 @@ PyTypeObject *get_python_yaml_collection_type(void) .tp_methods = py_yaml_collection_methods, .tp_getset = py_yaml_collection_getseters, - .tp_new = py_yaml_collection_new + + .tp_init = py_yaml_collection_init, + .tp_new = py_yaml_collection_new, }; @@ -233,7 +251,7 @@ PyTypeObject *get_python_yaml_collection_type(void) /****************************************************************************** * * -* Paramètres : module = module dont la définition est à compléter. * +* Paramètres : - * * * * Description : Prend en charge l'objet 'pychrysalide.....YamlCollection. * * * @@ -243,17 +261,24 @@ PyTypeObject *get_python_yaml_collection_type(void) * * ******************************************************************************/ -bool register_python_yaml_collection(PyObject *module) +bool ensure_python_yaml_collection_is_registered(void) { PyTypeObject *type; /* Type Python 'YamlCollection'*/ + PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ type = get_python_yaml_collection_type(); - dict = PyModule_GetDict(module); + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.yaml"); + + dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_YAML_COLLEC, type, get_python_yaml_node_type())) - return false; + if (!register_class_for_pygobject(dict, G_TYPE_YAML_COLLEC, type)) + return false; + + } return true; @@ -265,7 +290,7 @@ bool register_python_yaml_collection(PyObject *module) * Paramètres : arg = argument quelconque à tenter de convertir. * * dst = destination des valeurs récupérées en cas de succès. * * * -* Description : Tente de convertir en collection de noeuds de format Yaml. * +* Description : Tente de convertir en collection de noeuds de format YAML. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * @@ -287,7 +312,7 @@ int convert_to_yaml_collection(PyObject *arg, void *dst) break; case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml collection"); + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YAML collection"); break; case 1: diff --git a/plugins/yaml/python/collection.h b/plugins/yaml/python/collection.h index ab2caba..24875d0 100644 --- a/plugins/yaml/python/collection.h +++ b/plugins/yaml/python/collection.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * collection.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/collection.h" * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -35,9 +35,9 @@ PyTypeObject *get_python_yaml_collection_type(void); /* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlCollection'. */ -bool register_python_yaml_collection(PyObject *); +bool ensure_python_yaml_collection_is_registered(void); -/* Tente de convertir en collection de noeuds de format Yaml. */ +/* Tente de convertir en collection de noeuds de format YAML. */ int convert_to_yaml_collection(PyObject *, void *); diff --git a/plugins/yaml/python/constants.c b/plugins/yaml/python/constants.c new file mode 100644 index 0000000..ff04584 --- /dev/null +++ b/plugins/yaml/python/constants.c @@ -0,0 +1,127 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.c - prise en charge des constantes liées à YAML + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "constants.h" + + +#include <plugins/pychrysalide/helpers.h> + + +#include "../pair.h" + + + +/****************************************************************************** +* * +* Paramètres : type = type dont le dictionnaire est à compléter. * +* * +* Description : Définit les constantes relatives au noeuds principaux. * +* * +* Retour : true en cas de succès de l'opération, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool define_yaml_pair_constants(PyTypeObject *type) +{ + bool result; /* Bilan à retourner */ + PyObject *values; /* Groupe de valeurs à établir */ + + values = PyDict_New(); + + result = add_const_to_group(values, "PLAIN", YOS_PLAIN); + if (result) result = add_const_to_group(values, "SINGLE_QUOTED", YOS_SINGLE_QUOTED); + if (result) result = add_const_to_group(values, "DOUBLE_QUOTED", YOS_DOUBLE_QUOTED); + + if (!result) + { + Py_DECREF(values); + goto exit; + } + + result = attach_constants_group_to_type(type, false, "YamlOriginalStyle", values, + "Original style of scalar YAML nodes."); + + exit: + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : arg = argument quelconque à tenter de convertir. * +* dst = destination des valeurs récupérées en cas de succès. * +* * +* Description : Tente de convertir en constante YamlOriginalStyle. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_yaml_pair_original_style(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + unsigned long value; /* Valeur transcrite */ + + result = PyObject_IsInstance(arg, (PyObject *)&PyLong_Type); + + switch (result) + { + case -1: + /* L'exception est déjà fixée par Python */ + result = 0; + break; + + case 0: + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YamlOriginalStyle"); + break; + + case 1: + value = PyLong_AsUnsignedLong(arg); + + if (value > YOS_DOUBLE_QUOTED) + { + PyErr_SetString(PyExc_TypeError, "invalid value for YamlOriginalStyle"); + result = 0; + } + + else + *((YamlOriginalStyle *)dst) = value; + + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/yaml/python/constants.h b/plugins/yaml/python/constants.h new file mode 100644 index 0000000..d31bb69 --- /dev/null +++ b/plugins/yaml/python/constants.h @@ -0,0 +1,42 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * constants.h - prototypes pour la prise en charge des constantes liées à YAML + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_YAML_PYTHON_CONSTANTS_H +#define _PLUGINS_YAML_PYTHON_CONSTANTS_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit les constantes relatives au noeuds principaux. */ +bool define_yaml_pair_constants(PyTypeObject *); + +/* Tente de convertir en constante YamlOriginalStyle. */ +int convert_to_yaml_pair_original_style(PyObject *, void *); + + + +#endif /* _PLUGINS_YAML_PYTHON_CONSTANTS_H */ diff --git a/plugins/yaml/python/module.c b/plugins/yaml/python/module.c index 90823e8..3d6a4e8 100644 --- a/plugins/yaml/python/module.c +++ b/plugins/yaml/python/module.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * module.c - intégration du répertoire yaml en tant que module * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -34,12 +34,9 @@ #include "collection.h" -#include "line.h" #include "node.h" #include "pair.h" -#include "reader.h" -#include "scalar.h" -#include "tree.h" +#include "parser.h" @@ -62,7 +59,12 @@ bool add_yaml_module_to_python_module(void) PyObject *module; /* Sous-module mis en place */ #define PYCHRYSALIDE_PLUGINS_YAML_DOC \ - "yaml is a module providing access to Yaml content." + "yaml is a module providing access to YAML content.\n" \ + "\n" \ + "The parsing is provided by an external library: " \ + " https://github.com/yaml/libyaml . The Python module only" \ + " creates some glue to access YAML content from GObject" \ + " code." static PyModuleDef py_chrysalide_yaml_module = { @@ -105,19 +107,12 @@ bool add_yaml_module_to_python_module(void) bool populate_yaml_module(void) { bool result; /* Bilan à retourner */ - PyObject *module; /* Module à recompléter */ - result = true; + result = populate_yaml_module_with_parsers(); - module = get_access_to_python_module("pychrysalide.plugins.yaml"); - - if (result) result = register_python_yaml_node(module); - if (result) result = register_python_yaml_collection(module); - if (result) result = register_python_yaml_line(module); - if (result) result = register_python_yaml_pair(module); - if (result) result = register_python_yaml_reader(module); - if (result) result = register_python_yaml_scalar(module); - if (result) result = register_python_yaml_tree(module); + if (result) result = ensure_python_yaml_node_is_registered(); + if (result) result = ensure_python_yaml_collection_is_registered(); + if (result) result = ensure_python_yaml_pair_is_registered(); assert(result); diff --git a/plugins/yaml/python/node.c b/plugins/yaml/python/node.c index 7db6e59..7d2fef0 100644 --- a/plugins/yaml/python/node.c +++ b/plugins/yaml/python/node.c @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * node.c - équivalent Python du fichier "plugins/yaml/node.c" * - * Copyright (C) 2019-2020 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -28,101 +28,55 @@ #include <pygobject.h> +#include <plugins/pychrysalide/access.h> #include <plugins/pychrysalide/helpers.h> -#include "collection.h" -#include "line.h" #include "../node.h" -#define YAML_NODE_DOC \ - "YamlNode handles a node in a Yaml tree.\n" \ - "\n" \ - "There are three kinds of node contents defined in the Yaml specifications:\n" \ - "* scalar, implemented by the pychrysalide.plugins.yaml.YamlScalar object.\n" \ - "* sequence and mapping, implemented by the pychrysalide.plugins.yaml.YamlCollection object." - - +CREATE_DYN_ABSTRACT_CONSTRUCTOR(yaml_node, G_TYPE_YAML_NODE, NULL); -/* Recherche les noeuds correspondant à un chemin. */ -static PyObject *py_yaml_node_find_by_path(PyObject *, PyObject *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_yaml_node_init(PyObject *, PyObject *, PyObject *); -/* Recherche l'unique noeud correspondant à un chemin. */ -static PyObject *py_yaml_node_find_one_by_path(PyObject *, PyObject *); - -/* Fournit la ligne d'origine associée à un noeud. */ -static PyObject *py_yaml_node_get_yaml_line(PyObject *, void *); +/* Recherche le premier noeud correspondant à un chemin. */ +static PyObject *py_yaml_node_find_first_by_path(PyObject *, PyObject *); /****************************************************************************** * * -* Paramètres : self = variable non utilisée ici. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Recherche les noeuds correspondant à un chemin. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Liste de noeuds trouvés, éventuellement vide. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_node_find_by_path(PyObject *self, PyObject *args) +static int py_yaml_node_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - int prepare; /* Orientation des résultats */ - const char *path; /* Chemin d'accès à traiter */ int ret; /* Bilan de lecture des args. */ - GYamlNode *node; /* Version GLib du noeud */ - GYamlNode **found; /* Créations GLib à transmettre*/ - size_t count; /* Quantité de trouvailles */ - size_t i; /* Boucle de parcours */ - -#define YAML_NODE_FIND_BY_PATH_METHOD PYTHON_METHOD_DEF \ -( \ - find_by_path, "path, /, prepare=False", \ - METH_VARARGS, py_yaml_node, \ - "Find nodes from a Yaml node using a path.\n" \ - "\n" \ - "Paths are node keys separated by '/', such as '/my/path/to/node'." \ - "\n" \ - "In case where the path ends with a trailing '/', the operation can" \ - " be used to prepare a further look by returning a node which can be" \ - " searched by a new call to this function instead of returning all its" \ - " contained nodes." \ -) - - prepare = 0; - ret = PyArg_ParseTuple(args, "s|p", &path, &prepare); - if (!ret) return NULL; - - node = G_YAML_NODE(pygobject_get(self)); - - g_yaml_node_find_by_path(node, path, prepare, &found, &count); - - result = PyTuple_New(count); - - for (i = 0; i < count; i++) - { -#ifndef NDEBUG - ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i]))); - assert(ret == 0); -#else - PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i]))); -#endif - - g_object_unref(G_OBJECT(found[i])); +#define YAML_NODE_DOC \ + "YamlNode handles a node in a YAML tree.\n" \ + "\n" \ + "There are two kinds of node contents defined in the YAML specifications:\n" \ + "* pair, implemented by the pychrysalide.plugins.yaml.YamlPair object;\n" \ + "* sequence and mapping, implemented by the pychrysalide.plugins.yaml.YamlCollection object." - } + /* Initialisation d'un objet GLib */ - if (found != NULL) - free(found); + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; - return result; + return 0; } @@ -132,103 +86,55 @@ static PyObject *py_yaml_node_find_by_path(PyObject *self, PyObject *args) * Paramètres : self = variable non utilisée ici. * * args = arguments fournis à l'appel. * * * -* Description : Recherche l'unique noeud correspondant à un chemin. * +* Description : Recherche le premier noeud correspondant à un chemin. * * * -* Retour : Noeud avec correspondance établie ou None. * +* Retour : Noeud avec la correspondance établie ou None si non trouvé. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_node_find_one_by_path(PyObject *self, PyObject *args) +static PyObject *py_yaml_node_find_first_by_path(PyObject *self, PyObject *args) { PyObject *result; /* Instance à retourner */ - int prepare; /* Orientation des résultats */ const char *path; /* Chemin d'accès à traiter */ int ret; /* Bilan de lecture des args. */ GYamlNode *node; /* Version GLib du noeud */ - GYamlNode *found; /* Création GLib à transmettre */ + GYamlNode *found; /* Créations GLib à transmettre*/ -#define YAML_NODE_FIND_ONE_BY_PATH_METHOD PYTHON_METHOD_DEF \ +#define YAML_NODE_FIND_FIRST_BY_PATH_METHOD PYTHON_METHOD_DEF \ ( \ - find_one_by_path, "path, /, prepare=False", \ + find_first_by_path, "path", \ METH_VARARGS, py_yaml_node, \ - "Find a given node from a Yaml node using a path.\n" \ + "Find the first node related to a path among the node YAML children.\n" \ "\n" \ "Paths are node keys separated by '/', such as '/my/path/to/node'." \ + " In case where the path ends with a trailing '/', the operation" \ + " matches the first next met node.\n" \ "\n" \ - "Only one node has to match the path for the function success." \ + "The *path* argument is expected to be a string value.\n" \ "\n" \ - "In case where the path ends with a trailing '/', the operation can" \ - " be used to prepare a further look by returning a node which can be" \ - " searched by a new call to this function instead of returning all its" \ - " contained nodes." \ + "The function returns a pychrysalide.plugins.yaml.YamlNode instance," \ + " or *None* if none found." \ ) - prepare = 0; - - ret = PyArg_ParseTuple(args, "s|p", &path, &prepare); + ret = PyArg_ParseTuple(args, "s", &path); if (!ret) return NULL; node = G_YAML_NODE(pygobject_get(self)); - found = g_yaml_node_find_one_by_path(node, path, prepare); + found = g_yaml_node_find_first_by_path(node, path); - if (found == NULL) - { - result = Py_None; - Py_INCREF(result); - } - else + if (found != NULL) { result = pygobject_new(G_OBJECT(found)); g_object_unref(G_OBJECT(found)); } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit la ligne principale associée à un noeud. * -* * -* Retour : Ligne Yaml à l'origine du noeud. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure) -{ - PyObject *result; /* Résultat à retourner */ - GYamlNode *node; /* Version GLib du noeud */ - GYamlLine *line; /* Line Yaml associée */ - -#define YAML_NODE_YAML_LINE_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - yaml_line, py_yaml_node, \ - "Orginal Yaml line linked to the node." \ -) - - node = G_YAML_NODE(pygobject_get(self)); - - line = g_yaml_node_get_yaml_line(node); - - if (line == NULL) + else { result = Py_None; Py_INCREF(result); } - else - { - result = pygobject_new(G_OBJECT(line)); - g_object_unref(G_OBJECT(line)); - } return result; @@ -250,13 +156,11 @@ static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure) PyTypeObject *get_python_yaml_node_type(void) { static PyMethodDef py_yaml_node_methods[] = { - YAML_NODE_FIND_BY_PATH_METHOD, - YAML_NODE_FIND_ONE_BY_PATH_METHOD, + YAML_NODE_FIND_FIRST_BY_PATH_METHOD, { NULL } }; static PyGetSetDef py_yaml_node_getseters[] = { - YAML_NODE_YAML_LINE_ATTRIB, { NULL } }; @@ -273,7 +177,9 @@ PyTypeObject *get_python_yaml_node_type(void) .tp_methods = py_yaml_node_methods, .tp_getset = py_yaml_node_getseters, - .tp_new = no_python_constructor_allowed + + .tp_init = py_yaml_node_init, + .tp_new = py_yaml_node_new, }; @@ -284,7 +190,7 @@ PyTypeObject *get_python_yaml_node_type(void) /****************************************************************************** * * -* Paramètres : module = module dont la définition est à compléter. * +* Paramètres : - * * * * Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlNode. * * * @@ -294,17 +200,24 @@ PyTypeObject *get_python_yaml_node_type(void) * * ******************************************************************************/ -bool register_python_yaml_node(PyObject *module) +bool ensure_python_yaml_node_is_registered(void) { PyTypeObject *type; /* Type Python 'YamlNode' */ + PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ type = get_python_yaml_node_type(); - dict = PyModule_GetDict(module); + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.yaml"); + + dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_YAML_NODE, type, &PyGObject_Type)) - return false; + if (!register_class_for_pygobject(dict, G_TYPE_YAML_NODE, type)) + return false; + + } return true; @@ -316,7 +229,7 @@ bool register_python_yaml_node(PyObject *module) * Paramètres : arg = argument quelconque à tenter de convertir. * * dst = destination des valeurs récupérées en cas de succès. * * * -* Description : Tente de convertir en noeud d'arborescence de format Yaml. * +* Description : Tente de convertir en noeud d'arborescence de format YAML. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * @@ -338,7 +251,7 @@ int convert_to_yaml_node(PyObject *arg, void *dst) break; case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml node"); + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YAML node"); break; case 1: diff --git a/plugins/yaml/python/node.h b/plugins/yaml/python/node.h index dc3686b..80d8a65 100644 --- a/plugins/yaml/python/node.h +++ b/plugins/yaml/python/node.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * node.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/node.h" * - * Copyright (C) 2019 Cyrille Bagard + * Copyright (C) 2019-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -35,9 +35,9 @@ PyTypeObject *get_python_yaml_node_type(void); /* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlNode'. */ -bool register_python_yaml_node(PyObject *); +bool ensure_python_yaml_node_is_registered(void); -/* Tente de convertir en noeud d'arborescence de format Yaml. */ +/* Tente de convertir en noeud d'arborescence de format YAML. */ int convert_to_yaml_node(PyObject *, void *); diff --git a/plugins/yaml/python/pair.c b/plugins/yaml/python/pair.c index db5597d..1fffbeb 100644 --- a/plugins/yaml/python/pair.c +++ b/plugins/yaml/python/pair.c @@ -26,74 +26,176 @@ #include <assert.h> +#include <malloc.h> #include <pygobject.h> +#include <i18n.h> +#include <plugins/pychrysalide/access.h> #include <plugins/pychrysalide/helpers.h> #include "collection.h" -#include "line.h" +#include "constants.h" #include "node.h" -#include "../pair.h" +#include "../pair-int.h" -/* Crée un nouvel objet Python de type 'YamlPair'. */ -static PyObject *py_yaml_pair_new(PyTypeObject *, PyObject *, PyObject *); +CREATE_DYN_CONSTRUCTOR(yaml_pair, G_TYPE_YAML_PAIR); -/* Fournit la clef représentée dans une paire en Yaml. */ +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_yaml_pair_init(PyObject *, PyObject *, PyObject *); + +/* Rassemble une éventuelle séquence de valeurs attachées. */ +static PyObject *py_yaml_pair_aggregate_value(PyObject *, PyObject *); + +/* Fournit la clef représentée dans une paire en YAML. */ static PyObject *py_yaml_pair_get_key(PyObject *, void *); -/* Fournit l'éventuelle valeur d'une paire en Yaml. */ +/* Indique le format d'origine YAML associé à la clef. */ +static PyObject *py_yaml_pair_get_key_style(PyObject *, void *); + +/* Fournit l'éventuelle valeur d'une paire en YAML. */ static PyObject *py_yaml_pair_get_value(PyObject *, void *); -/* Attache une collection de noeuds Yaml à un noeud. */ -static int py_yaml_pair_set_collection(PyObject *, PyObject *, void *); +/* Indique le format d'origine YAML associé à la clef. */ +static PyObject *py_yaml_pair_get_value_style(PyObject *, void *); + +/* Attache une collection de noeuds YAML à un noeud. */ +static int py_yaml_pair_set_children(PyObject *, PyObject *, void *); /* Fournit une éventuelle collection rattachée à un noeud. */ -static PyObject *py_yaml_pair_get_collection(PyObject *, void *); +static PyObject *py_yaml_pair_get_children(PyObject *, void *); /****************************************************************************** * * -* Paramètres : type = type de l'objet à instancier. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * * kwds = arguments de type key=val fournis. * * * -* Description : Crée un nouvel objet Python de type 'YamlPair'. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance Python mise en place. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_pair_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int py_yaml_pair_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - GYamlLine *key; /* Ligne principale du noeud */ + YamlOriginalStyle kstyle; /* Format d'origine de la clef */ + const char *value; /* Eventuelle valeur associée */ + YamlOriginalStyle vstyle; /* Format d'origine de la val. */ + const char *key; /* Clef associée au noeud */ int ret; /* Bilan de lecture des args. */ - GYamlPair *node; /* Création GLib à transmettre */ + GYamlPair *pair; /* Création GLib à transmettre */ #define YAML_PAIR_DOC \ - "YamlPair handles a key/value pair node in a Yaml tree.\n" \ + "YamlPair handles a key/value pair node in a YAML tree.\n" \ "\n" \ "Instances can be created using the following constructor:\n" \ "\n" \ - " YamlPair(line)\n" \ + " YamlPair(key, kstyle=PLAIN, value=None, vstyle=PLAIN)\n" \ + "\n" \ + "Where *key* defines the name for the YAML node, and *value*" \ + " provides an optional direct value for the node. The *kstyle* and" \ + " *vstyle* arguements are" \ + " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle states" \ + " linking an original format to the provided relative strings.\n" \ + "\n" \ + "The two style are mainly used to aggregate children values into" \ + " a raw array. The following declarations are indeed equivalent" \ + " and pychrysalide.plugins.yaml.YamlPair.aggregate_value()" \ + " build the latter version from the former one:\n" \ "\n" \ - "Where key is the original Yaml line for the pair." + "a: [ 1, 2, 3 ]\n" \ + "\n" \ + "a:\n" \ + " - 1\n" \ + " - 2\n" \ + " - 3" \ + + /* Récupération des paramètres */ + + kstyle = YOS_PLAIN; + value = NULL; + vstyle = YOS_PLAIN; + + ret = PyArg_ParseTuple(args, "s|O&sO&", + &key, convert_to_yaml_pair_original_style, &kstyle, + &value, convert_to_yaml_pair_original_style, &vstyle); + if (!ret) return -1; + + /* Initialisation d'un objet GLib */ + + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; + + /* Eléments de base */ + + pair = G_YAML_PAIR(pygobject_get(self)); + + if (!g_yaml_pair_create(pair, key, kstyle, value, vstyle)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create YAML pair.")); + return -1; + + } + + return 0; + +} + + +/****************************************************************************** +* * +* Paramètres : self = serveur à manipuler. * +* args = arguments d'appel non utilisés ici. * +* * +* Description : Rassemble une éventuelle séquence de valeurs attachées. * +* * +* Retour : Valeur sous forme de chaîne de caractères ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_pair_aggregate_value(PyObject *self, PyObject *args) +{ + PyObject *result; /* Bilan à retourner */ + GYamlPair *node; /* Version GLib du type */ + char *value; /* Chaîne à transmettre */ - ret = PyArg_ParseTuple(args, "O&", &convert_to_yaml_line, &key); - if (!ret) return NULL; +#define YAML_PAIR_AGGREGATE_VALUE_METHOD PYTHON_METHOD_DEF \ +( \ + aggregate_value, "$self, /", \ + METH_NOARGS, py_yaml_pair, \ + "Provide the value linked to the YAML node, rebuilding" \ + " it from inner sequenced values if necessary and" \ + " possible." \ + "\n" \ + "The result is a string value, or *None* if none" \ + " available." \ +) - node = g_yaml_pair_new(key); + node = G_YAML_PAIR(pygobject_get(self)); + + value = g_yaml_pair_aggregate_value(node); + + if (value == NULL) + { + result = Py_None; + Py_INCREF(result); + } - g_object_ref_sink(G_OBJECT(node)); - result = pygobject_new(G_OBJECT(node)); - g_object_unref(node); + else + { + result = PyUnicode_FromString(value); + free(value); + } return result; @@ -105,7 +207,7 @@ static PyObject *py_yaml_pair_new(PyTypeObject *type, PyObject *args, PyObject * * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Fournit la clef représentée dans une paire en Yaml. * +* Description : Fournit la clef représentée dans une paire en YAML. * * * * Retour : Clef sous forme de chaîne de caractères. * * * @@ -122,7 +224,8 @@ static PyObject *py_yaml_pair_get_key(PyObject *self, void *closure) #define YAML_PAIR_KEY_ATTRIB PYTHON_GET_DEF_FULL \ ( \ key, py_yaml_pair, \ - "Key linked to the Yaml key/value pair node." \ + "Key linked to the YAML key/value pair node," \ + " as a string value." \ ) node = G_YAML_PAIR(pygobject_get(self)); @@ -142,7 +245,45 @@ static PyObject *py_yaml_pair_get_key(PyObject *self, void *closure) * Paramètres : self = objet Python concerné par l'appel. * * closure = non utilisé ici. * * * -* Description : Fournit l'éventuelle valeur d'une paire en Yaml. * +* Description : Indique le format d'origine YAML associé à la clef. * +* * +* Retour : Valeur renseignée lors du chargement du noeud. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_pair_get_key_style(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GYamlPair *node; /* Version GLib du noeud */ + YamlOriginalStyle style; /* Format à transmettre */ + +#define YAML_PAIR_KEY_STYLE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + key_style, py_yaml_pair, \ + "Original format for the YAML node Key, as a" \ + " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle" \ + " value." \ +) + + node = G_YAML_PAIR(pygobject_get(self)); + + style = g_yaml_pair_get_key_style(node); + + result = cast_with_constants_group_from_type(get_python_yaml_pair_type(), "YamlOriginalStyle", style); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit l'éventuelle valeur d'une paire en YAML. * * * * Retour : Valeur sous forme de chaîne de caractères ou None. * * * @@ -159,7 +300,8 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure) #define YAML_PAIR_VALUE_ATTRIB PYTHON_GET_DEF_FULL \ ( \ value, py_yaml_pair, \ - "Value linked to the Yaml key/value pair node or None." \ + "Value linked to the YAML key/value pair node, as a" \ + " string value, or *None* if none defined." \ ) node = G_YAML_PAIR(pygobject_get(self)); @@ -182,11 +324,52 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure) /****************************************************************************** * * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique le format d'origine YAML associé à la clef. * +* * +* Retour : Valeur renseignée lors du chargement du noeud. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_pair_get_value_style(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GYamlPair *node; /* Version GLib du noeud */ + YamlOriginalStyle style; /* Format à transmettre */ + +#define YAML_PAIR_VALUE_STYLE_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + value_style, py_yaml_pair, \ + "Original format for the YAML node Value, as a" \ + " pychrysalide.plugins.yaml.YamlPair.YamlOriginalStyle" \ + " value.\n" \ + "\n" \ + "Even if there is no value for the node, the default" \ + " style is returned: *PLAIN*." \ +) + + node = G_YAML_PAIR(pygobject_get(self)); + + style = g_yaml_pair_get_value_style(node); + + result = cast_with_constants_group_from_type(get_python_yaml_pair_type(), "YamlOriginalStyle", style); + + return result; + +} + + +/****************************************************************************** +* * * Paramètres : self = contenu binaire à manipuler. * -* value = collection de noeuds Yaml. * +* value = collection de noeuds YAML. * * closure = adresse non utilisée ici. * * * -* Description : Attache une collection de noeuds Yaml à un noeud. * +* Description : Attache une collection de noeuds YAML à un noeud. * * * * Retour : Jeu d'attributs liés au contenu courant. * * * @@ -194,28 +377,28 @@ static PyObject *py_yaml_pair_get_value(PyObject *self, void *closure) * * ******************************************************************************/ -static int py_yaml_pair_set_collection(PyObject *self, PyObject *value, void *closure) +static int py_yaml_pair_set_children(PyObject *self, PyObject *value, void *closure) { int result; /* Bilan à renvoyer */ GYamlPair *node; /* Version GLib du noeud */ - GYamlCollection *collec; /* Version GLib de la valeur */ + GYamlCollection *children; /* Version GLib de la valeur */ node = G_YAML_PAIR(pygobject_get(self)); if (value == Py_None) { - g_yaml_pair_set_collection(node, NULL); + g_yaml_pair_set_children(node, NULL); result = 0; } else { - if (!convert_to_yaml_collection(value, &collec)) + if (!convert_to_yaml_collection(value, &children)) result = -1; else { - g_yaml_pair_set_collection(node, collec); + g_yaml_pair_set_children(node, children); result = 0; } @@ -233,29 +416,31 @@ static int py_yaml_pair_set_collection(PyObject *self, PyObject *value, void *cl * * * Description : Fournit une éventuelle collection rattachée à un noeud. * * * -* Retour : Collection de noeuds Yaml ou None. * +* Retour : Collection de noeuds YAML ou None. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_pair_get_collection(PyObject *self, void *closure) +static PyObject *py_yaml_pair_get_children(PyObject *self, void *closure) { PyObject *result; /* Instance à retourner */ GYamlPair *node; /* Version GLib du noeud */ - GYamlCollection *collec; /* Collection à transmettre */ - -#define YAML_PAIR_COLLECTION_ATTRIB PYTHON_GETSET_DEF_FULL \ -( \ - collection, py_yaml_pair, \ - "Provide or define the collection of nodes attached to another Yaml node." \ + GYamlCollection *children; /* Collection à transmettre */ + +#define YAML_PAIR_CHILDREN_ATTRIB PYTHON_GETSET_DEF_FULL \ +( \ + children, py_yaml_pair, \ + "Provide or define the collection of nodes attached to another" \ + " YAML node. The collection, if defined, is handled as a" \ + " pychrysalide.plugins.yaml.YamlCollection instance." \ ) node = G_YAML_PAIR(pygobject_get(self)); - collec = g_yaml_pair_get_collection(node); + children = g_yaml_pair_get_children(node); - if (collec == NULL) + if (children == NULL) { result = Py_None; Py_INCREF(result); @@ -263,8 +448,8 @@ static PyObject *py_yaml_pair_get_collection(PyObject *self, void *closure) else { - result = pygobject_new(G_OBJECT(collec)); - g_object_unref(collec); + result = pygobject_new(G_OBJECT(children)); + g_object_unref(children); } return result; @@ -287,13 +472,16 @@ static PyObject *py_yaml_pair_get_collection(PyObject *self, void *closure) PyTypeObject *get_python_yaml_pair_type(void) { static PyMethodDef py_yaml_pair_methods[] = { + YAML_PAIR_AGGREGATE_VALUE_METHOD, { NULL } }; static PyGetSetDef py_yaml_pair_getseters[] = { YAML_PAIR_KEY_ATTRIB, + YAML_PAIR_KEY_STYLE_ATTRIB, YAML_PAIR_VALUE_ATTRIB, - YAML_PAIR_COLLECTION_ATTRIB, + YAML_PAIR_VALUE_STYLE_ATTRIB, + YAML_PAIR_CHILDREN_ATTRIB, { NULL } }; @@ -310,7 +498,9 @@ PyTypeObject *get_python_yaml_pair_type(void) .tp_methods = py_yaml_pair_methods, .tp_getset = py_yaml_pair_getseters, - .tp_new = py_yaml_pair_new + + .tp_init = py_yaml_pair_init, + .tp_new = py_yaml_pair_new, }; @@ -321,7 +511,7 @@ PyTypeObject *get_python_yaml_pair_type(void) /****************************************************************************** * * -* Paramètres : module = module dont la définition est à compléter. * +* Paramètres : - * * * * Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlPair. * * * @@ -331,17 +521,27 @@ PyTypeObject *get_python_yaml_pair_type(void) * * ******************************************************************************/ -bool register_python_yaml_pair(PyObject *module) +bool ensure_python_yaml_pair_is_registered(void) { PyTypeObject *type; /* Type Python 'YamlPair' */ + PyObject *module; /* Module à recompléter */ PyObject *dict; /* Dictionnaire du module */ type = get_python_yaml_pair_type(); - dict = PyModule_GetDict(module); + if (!PyType_HasFeature(type, Py_TPFLAGS_READY)) + { + module = get_access_to_python_module("pychrysalide.plugins.yaml"); + + dict = PyModule_GetDict(module); - if (!register_class_for_pygobject(dict, G_TYPE_YAML_PAIR, type, get_python_yaml_node_type())) - return false; + if (!register_class_for_pygobject(dict, G_TYPE_YAML_PAIR, type)) + return false; + + if (!define_yaml_pair_constants(type)) + return false; + + } return true; @@ -353,7 +553,7 @@ bool register_python_yaml_pair(PyObject *module) * Paramètres : arg = argument quelconque à tenter de convertir. * * dst = destination des valeurs récupérées en cas de succès. * * * -* Description : Tente de convertir en noeud d'arborescence de format Yaml. * +* Description : Tente de convertir en noeud d'arborescence de format YAML. * * * * Retour : Bilan de l'opération, voire indications supplémentaires. * * * @@ -375,7 +575,7 @@ int convert_to_yaml_pair(PyObject *arg, void *dst) break; case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml key/value pair"); + PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to YAML key/value pair"); break; case 1: diff --git a/plugins/yaml/python/pair.h b/plugins/yaml/python/pair.h index 2cafab8..b03b984 100644 --- a/plugins/yaml/python/pair.h +++ b/plugins/yaml/python/pair.h @@ -2,7 +2,7 @@ /* Chrysalide - Outil d'analyse de fichiers binaires * pair.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/pair.h" * - * Copyright (C) 2020 Cyrille Bagard + * Copyright (C) 2020-2023 Cyrille Bagard * * This file is part of Chrysalide. * @@ -35,9 +35,9 @@ PyTypeObject *get_python_yaml_pair_type(void); /* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlPair'. */ -bool register_python_yaml_pair(PyObject *); +bool ensure_python_yaml_pair_is_registered(void); -/* Tente de convertir en noeud d'arborescence de format Yaml. */ +/* Tente de convertir en noeud d'arborescence de format YAML. */ int convert_to_yaml_pair(PyObject *, void *); diff --git a/plugins/yaml/python/parser.c b/plugins/yaml/python/parser.c new file mode 100644 index 0000000..35a9090 --- /dev/null +++ b/plugins/yaml/python/parser.c @@ -0,0 +1,186 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.c - équivalent Python du fichier "plugins/yaml/parser.c" + * + * Copyright (C) 2019-2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#include "parser.h" + + +#include <pygobject.h> +#include <string.h> + + +#include <plugins/pychrysalide/access.h> +#include <plugins/pychrysalide/helpers.h> + + +#include "../parser.h" + + + +/* Crée une arborescence YAML pour contenu au format adapté. */ +static PyObject *py_yaml_parse_from_text(PyObject *, PyObject *); + +/* Crée une arborescence YAML pour fichier au format adapté. */ +static PyObject *py_yaml_parse_from_file(PyObject *, PyObject *); + + + +/****************************************************************************** +* * +* Paramètres : self = NULL car méthode statique. * +* args = arguments fournis lors de l'appel à la fonction. * +* * +* Description : Crée une arborescence YAML pour contenu au format adapté. * +* * +* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_parse_from_text(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + const char *text; /* Chaîne à traiter. */ + int ret; /* Bilan de lecture des args. */ + GYamlNode *root; /* Noeud racine obtenu */ + +#define YAML_PARSE_FROM_TEXT_METHOD PYTHON_METHOD_DEF \ +( \ + parse_from_text, "text, /", \ + METH_VARARGS, py_yaml, \ + "Parse a YAML content in order to build the relative YAML tree.\n" \ + "\n" \ + "The *text* argument is a string containg a markup content to" \ + " parse.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.yaml.YamlNode instance" \ + " or None in case of error." \ +) + + ret = PyArg_ParseTuple(args, "s", &text); + if (!ret) return NULL; + + root = parse_yaml_from_text(text, strlen(text)); + + if (root != NULL) + { + result = pygobject_new(G_OBJECT(root)); + g_object_unref(G_OBJECT(root)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = NULL car méthode statique. * +* args = arguments fournis lors de l'appel à la fonction. * +* * +* Description : Crée une arborescence YAML pour fichier au format adapté. * +* * +* Retour : Arborescence YAML mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_parse_from_file(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + const char *filename; /* Chemin vers des définitions */ + int ret; /* Bilan de lecture des args. */ + GYamlNode *root; /* Noeud racine obtenu */ + +#define YAML_PARSE_FROM_FILE_METHOD PYTHON_METHOD_DEF \ +( \ + parse_from_file, "filename, /", \ + METH_VARARGS, py_yaml, \ + "Parse a YAML content in order to build the relative YAML tree.\n" \ + "\n" \ + "The *filename* argument is a string for a path pointing to a YAML" \ + " content. This path can be either a real filename or a resource" \ + " URI.\n" \ + "\n" \ + "The result is a pychrysalide.plugins.yaml.YamlNode instance" \ + " or None in case of error." \ +) + + ret = PyArg_ParseTuple(args, "s", &filename); + if (!ret) return NULL; + + root = parse_yaml_from_file(filename); + + if (root != NULL) + { + result = pygobject_new(G_OBJECT(root)); + g_object_unref(G_OBJECT(root)); + } + else + { + result = Py_None; + Py_INCREF(result); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Définit une extension du module 'plugins.yaml' à compléter. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_yaml_module_with_parsers(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + static PyMethodDef py_yaml_methods[] = { + YAML_PARSE_FROM_TEXT_METHOD, + YAML_PARSE_FROM_FILE_METHOD, + { NULL } + }; + + module = get_access_to_python_module("pychrysalide.plugins.yaml"); + + result = register_python_module_methods(module, py_yaml_methods); + + return result; + +} diff --git a/plugins/yaml/python/parser.h b/plugins/yaml/python/parser.h new file mode 100644 index 0000000..18586ab --- /dev/null +++ b/plugins/yaml/python/parser.h @@ -0,0 +1,39 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * parser.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/parser.h" + * + * Copyright (C) 2019-2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +#ifndef _PLUGINS_YAML_PYTHON_PARSER_H +#define _PLUGINS_YAML_PYTHON_PARSER_H + + +#include <Python.h> +#include <stdbool.h> + + + +/* Définit une extension du module 'plugins.yaml' à compléter. */ +bool populate_yaml_module_with_parsers(void); + + + +#endif /* _PLUGINS_YAML_PYTHON_PARSER_H */ diff --git a/plugins/yaml/python/reader.c b/plugins/yaml/python/reader.c deleted file mode 100644 index f80623f..0000000 --- a/plugins/yaml/python/reader.c +++ /dev/null @@ -1,388 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * reader.c - équivalent Python du fichier "plugins/yaml/reader.c" - * - * Copyright (C) 2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "reader.h" - - -#include <pygobject.h> - - -#include <plugins/pychrysalide/helpers.h> - - -#include "../reader.h" - - - -#define YAML_READER_DOC \ - "YamlReader is the class which aims to provide a reader interface to Yaml content.\n" \ - "\n" \ - "When no input error, the Yaml content can be retrieved line by line or thanks to a tree." - - - -/* Crée un lecteur pour contenu au format Yaml. */ -static PyObject *py_yaml_reader_new_from_content(PyObject *, PyObject *); - -/* Crée un lecteur pour contenu au format Yaml. */ -static PyObject *py_yaml_reader_new_from_path(PyObject *, PyObject *); - -/* Fournit la liste des lignes lues depuis un contenu Yaml. */ -static PyObject *py_yaml_reader_get_lines(PyObject *, void *); - -/* Fournit l'arborescence associée à la lecture de lignes Yaml. */ -static PyObject *py_yaml_reader_get_tree(PyObject *, void *); - - - -/****************************************************************************** -* * -* Paramètres : self = variable non utilisée ici. * -* args = arguments fournis à l'appel. * -* * -* Description : Crée un lecteur pour contenu au format Yaml. * -* * -* Retour : Instance mise en place ou None en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_reader_new_from_content(PyObject *self, PyObject *args) -{ - PyObject *result; /* Instance à retourner */ - const char *content; /* Contenu brut au format Yaml */ - int length; /* Taille de ce contenu */ - int ret; /* Bilan de lecture des args. */ - GYamlReader *reader; /* Création GLib à transmettre */ - -#define YAML_READER_NEW_FROM_CONTENT_METHOD PYTHON_METHOD_DEF \ -( \ - new_from_content, "content", \ - METH_STATIC | METH_VARARGS, py_yaml_reader, \ - "Load a Yaml content." \ -) - - /** - * La taille doit être de type 'int' et non 'Py_ssize_t', sinon les 32 bits - * de poids fort ne sont pas initialisés ! - */ - - ret = PyArg_ParseTuple(args, "s#", &content, &length); - if (!ret) return NULL; - - reader = g_yaml_reader_new_from_content(content, length); - - if (reader == NULL) - { - result = Py_None; - Py_INCREF(result); - } - - else - { - g_object_ref_sink(G_OBJECT(reader)); - result = pygobject_new(G_OBJECT(reader)); - g_object_unref(reader); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = variable non utilisée ici. * -* args = arguments fournis à l'appel. * -* * -* Description : Crée un lecteur pour contenu au format Yaml. * -* * -* Retour : Instance mise en place ou None en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_reader_new_from_path(PyObject *self, PyObject *args) -{ - PyObject *result; /* Instance à retourner */ - const char *path; /* Chemin d'accès à un contenu */ - int ret; /* Bilan de lecture des args. */ - GYamlReader *reader; /* Création GLib à transmettre */ - -#define YAML_READER_NEW_FROM_PATH_METHOD PYTHON_METHOD_DEF \ -( \ - new_from_path, "path", \ - METH_STATIC | METH_VARARGS, py_yaml_reader, \ - "Load a Yaml content from a path.\n" \ - "\n" \ - "The path can be a filename or a resource URI." \ -) - - ret = PyArg_ParseTuple(args, "s", &path); - if (!ret) return NULL; - - reader = g_yaml_reader_new_from_path(path); - - if (reader == NULL) - { - result = Py_None; - Py_INCREF(result); - } - - else - { - g_object_ref_sink(G_OBJECT(reader)); - result = pygobject_new(G_OBJECT(reader)); - g_object_unref(reader); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit la liste des lignes lues depuis un contenu Yaml. * -* * -* Retour : Liste de lignes correspondant au contenu Yaml lu. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_reader_get_lines(PyObject *self, void *closure) -{ - PyObject *result; /* Résultat à retourner */ - GYamlReader *reader; /* Version GLib du type */ - size_t count; /* Quantité de lignes à traiter*/ - GYamlLine **lines; /* Liste de lignes lues */ - size_t i; /* Boucle de parcours */ -#ifndef NDEBUG - int ret; /* Bilan d'une insertion */ -#endif - -#define YAML_READER_LINES_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - lines, py_yaml_reader, \ - "List of Yaml lines processed by the reader." \ -) - - reader = G_YAML_READER(pygobject_get(self)); - - lines = g_yaml_reader_get_lines(reader, &count); - - result = PyTuple_New(count); - - for (i = 0; i < count; i++) - { -#ifndef NDEBUG - ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(lines[i]))); - assert(ret == 0); -#else - PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(lines[i]))); -#endif - - g_object_unref(G_OBJECT(lines[i])); - - } - - if (lines != NULL) - free(lines); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit l'arborescence associée à la lecture de lignes Yaml. * -* * -* Retour : Arborescence constituée par la lecture du contenu Yaml. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_reader_get_tree(PyObject *self, void *closure) -{ - PyObject *result; /* Résultat à retourner */ - GYamlReader *reader; /* Version GLib du type */ - GYamlTree *tree; /* Arborescence associée */ - -#define YAML_READER_TREE_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - tree, py_yaml_reader, \ - "Tree of all nodes built from the Yaml content." \ -) - - reader = G_YAML_READER(pygobject_get(self)); - - tree = g_yaml_reader_get_tree(reader); - - if (tree == NULL) - { - result = Py_None; - Py_INCREF(result); - } - else - { - result = pygobject_new(G_OBJECT(tree)); - g_object_unref(G_OBJECT(tree)); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Fournit un accès à une définition de type à diffuser. * -* * -* Retour : Définition d'objet pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PyTypeObject *get_python_yaml_reader_type(void) -{ - static PyMethodDef py_yaml_reader_methods[] = { - YAML_READER_NEW_FROM_CONTENT_METHOD, - YAML_READER_NEW_FROM_PATH_METHOD, - { NULL } - }; - - static PyGetSetDef py_yaml_reader_getseters[] = { - YAML_READER_LINES_ATTRIB, - YAML_READER_TREE_ATTRIB, - { NULL } - }; - - static PyTypeObject py_yaml_reader_type = { - - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "pychrysalide.plugins.yaml.YamlReader", - .tp_basicsize = sizeof(PyGObject), - - .tp_flags = Py_TPFLAGS_DEFAULT, - - .tp_doc = YAML_READER_DOC, - - .tp_methods = py_yaml_reader_methods, - .tp_getset = py_yaml_reader_getseters, - .tp_new = no_python_constructor_allowed - - }; - - return &py_yaml_reader_type; - -} - - -/****************************************************************************** -* * -* Paramètres : module = module dont la définition est à compléter. * -* * -* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlReader.* -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool register_python_yaml_reader(PyObject *module) -{ - PyTypeObject *type; /* Type Python 'YamlReader' */ - PyObject *dict; /* Dictionnaire du module */ - - type = get_python_yaml_reader_type(); - - dict = PyModule_GetDict(module); - - if (!register_class_for_pygobject(dict, G_TYPE_YAML_READER, type, &PyGObject_Type)) - return false; - - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : arg = argument quelconque à tenter de convertir. * -* dst = destination des valeurs récupérées en cas de succès. * -* * -* Description : Tente de convertir en lecteur de données au format Yaml. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_yaml_reader(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - - result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_reader_type()); - - switch (result) - { - case -1: - /* L'exception est déjà fixée par Python */ - result = 0; - break; - - case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml reader"); - break; - - case 1: - *((GYamlReader **)dst) = G_YAML_READER(pygobject_get(arg)); - break; - - default: - assert(false); - break; - - } - - return result; - -} diff --git a/plugins/yaml/python/tree.c b/plugins/yaml/python/tree.c deleted file mode 100644 index 7d28254..0000000 --- a/plugins/yaml/python/tree.c +++ /dev/null @@ -1,427 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * tree.c - équivalent Python du fichier "plugins/yaml/tree.c" - * - * Copyright (C) 2019-2020 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - */ - - -#include "tree.h" - - -#include <pygobject.h> - - -#include <i18n.h> -#include <plugins/pychrysalide/helpers.h> - - -#include "line.h" -#include "../tree.h" - - - -/* Crée un nouvel objet Python de type 'YamlTree'. */ -static PyObject *py_yaml_tree_new(PyTypeObject *, PyObject *, PyObject *); - -/* Recherche les noeuds correspondant à un chemin. */ -static PyObject *py_yaml_tree_find_by_path(PyObject *, PyObject *); - -/* Fournit le noeud constituant la racine d'arborescence Yaml. */ -static PyObject *py_yaml_tree_get_root(PyObject *, void *); - - - -/****************************************************************************** -* * -* Paramètres : type = type de l'objet à instancier. * -* args = arguments fournis à l'appel. * -* kwds = arguments de type key=val fournis. * -* * -* Description : Crée un nouvel objet Python de type 'YamlTree'. * -* * -* Retour : Instance Python mise en place. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *kwds) -{ - PyObject *result; /* Instance à retourner */ - PyObject *tuple; /* Liste de lignes Yaml */ - int ret; /* Bilan de lecture des args. */ - size_t count; /* Nombre d'éléments présents */ - GYamlLine **lines; /* Lignes au format Yaml */ - GYamlTree *tree; /* Création GLib à transmettre */ - size_t i; /* Boucle de parcours #1 */ - PyObject *item; /* Elément de la liste fournie */ - size_t k; /* Boucle de parcours #2 */ - -#define YAML_TREE_DOC \ - "YamlTree offers a hierarchical access to Yaml lines as a tree.\n" \ - "\n" \ - "Instances can be created using the following constructor:\n" \ - "\n" \ - " YamlTree(lines)" \ - "\n" \ - "Where lines are a tuple of Yaml lines used to built the tree." - - ret = PyArg_ParseTuple(args, "O!", &PyTuple_Type, &tuple); - if (!ret) return NULL; - - count = PyTuple_Size(tuple); - - lines = (GYamlLine **)malloc(count * sizeof(GYamlLine *)); - - tree = NULL; - - for (i = 0; i < count; i++) - { - item = PyTuple_GetItem(tuple, i); - - ret = convert_to_yaml_line(item, &lines[i]); - - if (ret == 0) - g_object_ref(G_OBJECT(lines[i])); - - else - goto arg_error; - - } - - tree = g_yaml_tree_new(lines, count); - - arg_error: - - for (k = 0; k < i; k++) - g_object_unref(G_OBJECT(lines[i])); - - free(lines); - - /* S'il y a eu une erreur... */ - if (i < count) return NULL; - - if (tree == NULL) - { - result = Py_None; - Py_INCREF(result); - } - - else - { - g_object_ref_sink(G_OBJECT(tree)); - result = pygobject_new(G_OBJECT(tree)); - g_object_unref(tree); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = variable non utilisée ici. * -* args = arguments fournis à l'appel. * -* * -* Description : Recherche les noeuds correspondant à un chemin. * -* * -* Retour : Liste de noeuds trouvés, éventuellement vide. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_tree_find_by_path(PyObject *self, PyObject *args) -{ - PyObject *result; /* Instance à retourner */ - int prepare; /* Orientation des résultats */ - const char *path; /* Chemin d'accès à traiter */ - int ret; /* Bilan de lecture des args. */ - GYamlTree *tree; /* Version GLib du type */ - GYamlNode **found; /* Créations GLib à transmettre*/ - size_t count; /* Quantité de trouvailles */ - size_t i; /* Boucle de parcours */ - -#define YAML_TREE_FIND_BY_PATH_METHOD PYTHON_METHOD_DEF \ -( \ - find_by_path, "path, /, prepare=False", \ - METH_VARARGS, py_yaml_tree, \ - "Find nodes in a Yaml tree using a path.\n" \ - "\n" \ - "Paths are node keys separated by '/', such as '/my/path/to/node'." \ - "\n" \ - "In case where the path ends with a trailing '/', the operation can" \ - " be used to prepare a further look by returning a node which can be" \ - " searched by a new call to this function instead of returning all its" \ - " contained nodes." \ -) - - prepare = 0; - - ret = PyArg_ParseTuple(args, "s|p", &path, &prepare); - if (!ret) return NULL; - - tree = G_YAML_TREE(pygobject_get(self)); - - g_yaml_tree_find_by_path(tree, path, prepare, &found, &count); - - result = PyTuple_New(count); - - for (i = 0; i < count; i++) - { -#ifndef NDEBUG - ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i]))); - assert(ret == 0); -#else - PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i]))); -#endif - - g_object_unref(G_OBJECT(found[i])); - - } - - if (found != NULL) - free(found); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = variable non utilisée ici. * -* args = arguments fournis à l'appel. * -* * -* Description : Recherche l'unique noeud correspondant à un chemin. * -* * -* Retour : Noeud avec correspondance établie ou None. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_tree_find_one_by_path(PyObject *self, PyObject *args) -{ - PyObject *result; /* Instance à retourner */ - int prepare; /* Orientation des résultats */ - const char *path; /* Chemin d'accès à traiter */ - int ret; /* Bilan de lecture des args. */ - GYamlTree *tree; /* Version GLib du type */ - GYamlNode *found; /* Création GLib à transmettre */ - -#define YAML_TREE_FIND_ONE_BY_PATH_METHOD PYTHON_METHOD_DEF \ -( \ - find_one_by_path, "path, /, prepare=False", \ - METH_VARARGS, py_yaml_tree, \ - "Find a given node from a Yaml node using a path.\n" \ - "\n" \ - "Paths are node keys separated by '/', such as '/my/path/to/node'." \ - "\n" \ - "Only one node has to match the path for the function success." \ - "\n" \ - "In case where the path ends with a trailing '/', the operation can" \ - " be used to prepare a further look by returning a node which can be" \ - " searched by a new call to this function instead of returning all its" \ - " contained nodes." \ -) - - prepare = 0; - - ret = PyArg_ParseTuple(args, "s|p", &path, &prepare); - if (!ret) return NULL; - - tree = G_YAML_TREE(pygobject_get(self)); - - found = g_yaml_tree_find_one_by_path(tree, path, prepare); - - if (found == NULL) - { - result = Py_None; - Py_INCREF(result); - } - else - { - result = pygobject_new(G_OBJECT(found)); - g_object_unref(G_OBJECT(found)); - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : self = objet Python concerné par l'appel. * -* closure = non utilisé ici. * -* * -* Description : Fournit le noeud constituant la racine d'arborescence Yaml. * -* * -* Retour : Noeud constituant la racine de l'arborescence. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_tree_get_root(PyObject *self, void *closure) -{ - PyObject *result; /* Résultat à retourner */ - GYamlTree *tree; /* Version GLib du type */ - GYamlNode *root; /* Noeud racine d'arborescence */ - -#define YAML_TREE_ROOT_ATTRIB PYTHON_GET_DEF_FULL \ -( \ - root, py_yaml_tree, \ - "Yaml node which is the root of the whole tree nodes." \ -) - - tree = G_YAML_TREE(pygobject_get(self)); - - root = g_yaml_tree_get_root(tree); - - result = pygobject_new(G_OBJECT(root)); - g_object_unref(G_OBJECT(root)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : - * -* * -* Description : Fournit un accès à une définition de type à diffuser. * -* * -* Retour : Définition d'objet pour Python. * -* * -* Remarques : - * -* * -******************************************************************************/ - -PyTypeObject *get_python_yaml_tree_type(void) -{ - static PyMethodDef py_yaml_tree_methods[] = { - YAML_TREE_FIND_BY_PATH_METHOD, - YAML_TREE_FIND_ONE_BY_PATH_METHOD, - { NULL } - }; - - static PyGetSetDef py_yaml_tree_getseters[] = { - YAML_TREE_ROOT_ATTRIB, - { NULL } - }; - - static PyTypeObject py_yaml_tree_type = { - - PyVarObject_HEAD_INIT(NULL, 0) - - .tp_name = "pychrysalide.plugins.yaml.YamlTree", - .tp_basicsize = sizeof(PyGObject), - - .tp_flags = Py_TPFLAGS_DEFAULT, - - .tp_doc = YAML_TREE_DOC, - - .tp_methods = py_yaml_tree_methods, - .tp_getset = py_yaml_tree_getseters, - .tp_new = py_yaml_tree_new - - }; - - return &py_yaml_tree_type; - -} - - -/****************************************************************************** -* * -* Paramètres : module = module dont la définition est à compléter. * -* * -* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlTree. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -bool register_python_yaml_tree(PyObject *module) -{ - PyTypeObject *type; /* Type Python 'YamlTree' */ - PyObject *dict; /* Dictionnaire du module */ - - type = get_python_yaml_tree_type(); - - dict = PyModule_GetDict(module); - - if (!register_class_for_pygobject(dict, G_TYPE_YAML_TREE, type, &PyGObject_Type)) - return false; - - return true; - -} - - -/****************************************************************************** -* * -* Paramètres : arg = argument quelconque à tenter de convertir. * -* dst = destination des valeurs récupérées en cas de succès. * -* * -* Description : Tente de convertir en arborescence de lignes au format Yaml. * -* * -* Retour : Bilan de l'opération, voire indications supplémentaires. * -* * -* Remarques : - * -* * -******************************************************************************/ - -int convert_to_yaml_tree(PyObject *arg, void *dst) -{ - int result; /* Bilan à retourner */ - - result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_tree_type()); - - switch (result) - { - case -1: - /* L'exception est déjà fixée par Python */ - result = 0; - break; - - case 0: - PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml tree"); - break; - - case 1: - *((GYamlTree **)dst) = G_YAML_TREE(pygobject_get(arg)); - break; - - default: - assert(false); - break; - - } - - return result; - -} diff --git a/plugins/yaml/reader.h b/plugins/yaml/reader.h deleted file mode 100644 index 3e5ce48..0000000 --- a/plugins/yaml/reader.h +++ /dev/null @@ -1,69 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * reader.h - prototypes pour le lecteur de contenu Yaml - * - * Copyright (C) 2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. - */ - - -#ifndef PLUGINS_YAML_READER_H -#define PLUGINS_YAML_READER_H - - -#include <glib-object.h> -#include <stdbool.h> - - -#include "line.h" -#include "tree.h" - - - -#define G_TYPE_YAML_READER g_yaml_reader_get_type() -#define G_YAML_READER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_READER, GYamlReader)) -#define G_IS_YAML_READER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_READER)) -#define G_YAML_READER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_READER, GYamlReaderClass)) -#define G_IS_YAML_READER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_READER)) -#define G_YAML_READER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_READER, GYamlReaderClass)) - - -/* Lecteur de contenu Yaml (instance) */ -typedef struct _GYamlReader GYamlReader; - -/* Lecteur de contenu Yaml (classe) */ -typedef struct _GYamlReaderClass GYamlReaderClass; - - -/* Indique le type défini pour un lecteur de contenu Yaml. */ -GType g_yaml_reader_get_type(void); - -/* Crée un lecteur pour contenu au format Yaml. */ -GYamlReader *g_yaml_reader_new_from_content(const char *, size_t); - -/* Crée un lecteur pour contenu au format Yaml. */ -GYamlReader *g_yaml_reader_new_from_path(const char *); - -/* Fournit la liste des lignes lues depuis un contenu Yaml. */ -GYamlLine **g_yaml_reader_get_lines(const GYamlReader *, size_t *); - -/* Fournit l'arborescence associée à la lecture de lignes Yaml. */ -GYamlTree *g_yaml_reader_get_tree(const GYamlReader *); - - - -#endif /* PLUGINS_YAML_READER_H */ diff --git a/plugins/yaml/scalar.h b/plugins/yaml/scalar.h deleted file mode 100644 index 5403e85..0000000 --- a/plugins/yaml/scalar.h +++ /dev/null @@ -1,72 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * scalar.h - prototypes pour un noeud Yaml de type "scalar" - * - * Copyright (C) 2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. - */ - - -#ifndef PLUGINS_YAML_SCALAR_H -#define PLUGINS_YAML_SCALAR_H - - -#include <glib-object.h> -#include <stdbool.h> - - -#include "line.h" -#include "node.h" - - -/* Depuis collection.h : collection de noeuds au format Yaml (instance) */ -typedef struct _GYamlCollection GYamlCollection; - - -#define G_TYPE_YAML_SCALAR g_yaml_scalar_get_type() -#define G_YAML_SCALAR(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_SCALAR, GYamlScalar)) -#define G_IS_YAML_SCALAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_SCALAR)) -#define G_YAML_SCALAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_SCALAR, GYamlScalarClass)) -#define G_IS_YAML_SCALAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_SCALAR)) -#define G_YAML_SCALAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_SCALAR, GYamlScalarClass)) - - -/* Noeud d'une arborescence au format Yaml (instance) */ -typedef struct _GYamlScalar GYamlScalar; - -/* Noeud d'une arborescence au format Yaml (classe) */ -typedef struct _GYamlScalarClass GYamlScalarClass; - - -/* Indique le type défini pour un noeud d'arborescence Yaml. */ -GType g_yaml_scalar_get_type(void); - -/* Construit un noeud d'arborescence Yaml. */ -GYamlScalar *g_yaml_scalar_new(GYamlLine *); - -/* Fournit la ligne principale associée à un noeud. */ -GYamlLine *g_yaml_scalar_get_yaml_line(const GYamlScalar *); - -/* Attache une collection de noeuds Yaml à un noeud. */ -void g_yaml_scalar_set_collection(GYamlScalar *, GYamlCollection *); - -/* Fournit une éventuelle collection rattachée à un noeud. */ -GYamlCollection *g_yaml_scalar_get_collection(const GYamlScalar *); - - - -#endif /* PLUGINS_YAML_SCALAR_H */ diff --git a/plugins/yaml/tree.c b/plugins/yaml/tree.c deleted file mode 100644 index 9125302..0000000 --- a/plugins/yaml/tree.c +++ /dev/null @@ -1,421 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * tree.c - ligne de contenu Yaml - * - * Copyright (C) 2019-2020 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. - */ - - -#include "tree.h" - - -#include <assert.h> -#include <malloc.h> -#include <string.h> - - -#include <i18n.h> -#include <core/logs.h> - - -#include "pair.h" -#include "collection.h" - - - -/* Arborescence de lignes au format Yaml (instance) */ -struct _GYamlTree -{ - GObject parent; /* A laisser en premier */ - - GYamlNode *root; /* Racine des noeuds */ - -}; - -/* Arborescence de lignes au format Yaml (classe) */ -struct _GYamlTreeClass -{ - GObjectClass parent; /* A laisser en premier */ - -}; - - -/* Initialise la classe des arborescence de lignes Yaml. */ -static void g_yaml_tree_class_init(GYamlTreeClass *); - -/* Initialise une instance d'arborescence de lignes Yaml. */ -static void g_yaml_tree_init(GYamlTree *); - -/* Supprime toutes les références externes. */ -static void g_yaml_tree_dispose(GYamlTree *); - -/* Procède à la libération totale de la mémoire. */ -static void g_yaml_tree_finalize(GYamlTree *); - -/* Construit une collection de noeuds avec une arborescence. */ -static bool g_yaml_tree_build_node(GYamlCollection *, GYamlLine **, size_t, size_t, size_t *); - - - -/* Indique le type défini pour une arborescence de lignes au format Yaml. */ -G_DEFINE_TYPE(GYamlTree, g_yaml_tree, G_TYPE_OBJECT); - - -/****************************************************************************** -* * -* Paramètres : klass = classe à initialiser. * -* * -* Description : Initialise la classe des arborescence de lignes Yaml. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_yaml_tree_class_init(GYamlTreeClass *klass) -{ - GObjectClass *object; /* Autre version de la classe */ - - object = G_OBJECT_CLASS(klass); - - object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_tree_dispose; - object->finalize = (GObjectFinalizeFunc)g_yaml_tree_finalize; - -} - - -/****************************************************************************** -* * -* Paramètres : tree = instance à initialiser. * -* * -* Description : Initialise une instance d'arborescence de lignes Yaml. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_yaml_tree_init(GYamlTree *tree) -{ - tree->root = NULL; - -} - - -/****************************************************************************** -* * -* Paramètres : tree = instance d'objet GLib à traiter. * -* * -* Description : Supprime toutes les références externes. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_yaml_tree_dispose(GYamlTree *tree) -{ - g_clear_object(&tree->root); - - G_OBJECT_CLASS(g_yaml_tree_parent_class)->dispose(G_OBJECT(tree)); - -} - - -/****************************************************************************** -* * -* Paramètres : tree = instance d'objet GLib à traiter. * -* * -* Description : Procède à la libération totale de la mémoire. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -static void g_yaml_tree_finalize(GYamlTree *tree) -{ - G_OBJECT_CLASS(g_yaml_tree_parent_class)->finalize(G_OBJECT(tree)); - -} - - -/****************************************************************************** -* * -* Paramètres : lines = ensemble de lignes à constituer en arborescence. * -* count = taille de cet ensemble de lignes. * -* * -* Description : Construit une arborescence à partir de lignes Yaml. * -* * -* Retour : Instance mise en place ou NULL en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GYamlTree *g_yaml_tree_new(GYamlLine **lines, size_t count) -{ - GYamlTree *result; /* Structure à retourner */ - GYamlCollection *collec; /* Collection de noeuds */ - size_t indent; /* Indentation initiale */ - size_t processed; /* Quantité de noeuds traités */ - bool status; /* Bilan de construction */ - - result = g_object_new(G_TYPE_YAML_TREE, NULL); - - if (count > 0) - { - collec = g_yaml_collection_new(g_yaml_line_is_list_item(lines[0])); - - result->root = G_YAML_NODE(collec); - - indent = g_yaml_line_count_indent(lines[0]); - processed = 0; - - status = g_yaml_tree_build_node(collec, lines, count, indent, &processed); - - if (status) - assert(processed == count); - - else - { - g_object_unref(G_OBJECT(result)); - result = NULL; - } - - } - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : lines = ensemble de lignes à constituer en arborescence. * -* count = taille de cet ensemble de lignes. * -* expected = niveau d'identation attendu. * -* cur = position courante dans les lignes. [OUT] * -* * -* Description : Construit une collection de noeuds avec une arborescence. * -* * -* Retour : Bilan de l'opération. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static bool g_yaml_tree_build_node(GYamlCollection *collec, GYamlLine **lines, size_t count, size_t expected, size_t *cur) -{ - bool result; /* Bilan à retourner */ - bool first; /* Marque d'un premier élément */ - GYamlNode *last; /* Mémorisation du dernier */ - GYamlLine *line; /* Ligne de parcours courante */ - size_t indent; /* Indentation de ligne */ - bool is_item; /* Elément d'une liste ? */ - GYamlCollection *sub; /* Nouvelle sous-collection */ - - result = true; - - first = true; - last = NULL; - - for (; *cur < count; ) - { - line = lines[*cur]; - - indent = g_yaml_line_count_indent(line); - is_item = g_yaml_line_is_list_item(line); - - /** - * Si la première ligne traitée commence par un élément de liste, - * alors un appel parent a constitué une collection qui n'est pas une séquence. - * - * L'objectif est de créer une simple association de 'clefs: valeurs'. - * - * Si la collection n'est pas adaptée, alors le parcours n'est pas encore - * arrivé à ce stade de construction. - */ - if (first && is_item && !g_yaml_collection_is_sequence(collec)) - { - indent += 2; /* 2 == strlen("- ") */ - is_item = false; - } - - first = false; - - /* Fin de l'ensemble courant */ - if (indent < expected) - goto done; - - /* Début d'un sous-ensemble */ - else if (indent > expected) - { - if (last == NULL) - { - result = false; - goto done; - } - - sub = g_yaml_collection_new(is_item); - g_yaml_pair_set_collection(G_YAML_PAIR(last), sub); - - result = g_yaml_tree_build_node(sub, lines, count, indent, cur); - if (!result) goto done; - - } - - /* Elément de même niveau */ - else - { - if (is_item) - { - /* Vérification de cohérence */ - if (!g_yaml_collection_is_sequence(collec)) - { - log_variadic_message(LMT_BAD_BINARY, _("A list item was expected at line %zu"), - g_yaml_line_get_number(line)); - - result = false; - goto done; - - } - - sub = g_yaml_collection_new(false); - g_yaml_collection_add_node(collec, G_YAML_NODE(sub)); - - result = g_yaml_tree_build_node(sub, lines, count, expected + 2 /* 2 == strlen("- ") */, cur); - if (!result) goto done; - - } - - else - { - /* Vérification de cohérence */ - if (g_yaml_collection_is_sequence(collec)) - { - log_variadic_message(LMT_BAD_BINARY, _("A mapping item was expected at line %zu"), - g_yaml_line_get_number(line)); - - - result = false; - goto done; - - } - - last = G_YAML_NODE(g_yaml_pair_new(line)); - - if (last == NULL) - { - result = false; - goto done; - } - - g_yaml_collection_add_node(collec, last); - - (*cur)++; - - } - - } - - } - - done: - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : tree = ligne au format Yaml à consulter. * -* * -* Description : Fournit le noeud constituant la racine d'arborescence Yaml. * -* * -* Retour : Noeud constituant la racine de l'arborescence. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GYamlNode *g_yaml_tree_get_root(const GYamlTree *tree) -{ - GYamlNode *result; /* Liste à retourner */ - - result = tree->root; - - if (result != NULL) - g_object_ref(G_OBJECT(result)); - - return result; - -} - - -/****************************************************************************** -* * -* Paramètres : tree = ligne au format Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* nodes = liste de noeuds avec correspondance établie. [OUT] * -* count = quantité de ces noeuds. [OUT] * -* * -* Description : Recherche les noeuds correspondant à un chemin. * -* * -* Retour : - * -* * -* Remarques : - * -* * -******************************************************************************/ - -void g_yaml_tree_find_by_path(const GYamlTree *tree, const char *path, bool prepare, GYamlNode ***nodes, size_t *count) -{ - g_yaml_node_find_by_path(tree->root, path, prepare, nodes, count); - -} - - -/****************************************************************************** -* * -* Paramètres : tree = ligne au format Yaml à consulter. * -* path = chemin d'accès à parcourir. * -* prepare = indication sur une préparation d'un prochain appel.* -* * -* Description : Recherche l'unique noeud correspondant à un chemin. * -* * -* Retour : Noeud avec correspondance établie ou NULL. * -* * -* Remarques : - * -* * -******************************************************************************/ - -GYamlNode *g_yaml_tree_find_one_by_path(GYamlTree *tree, const char *path, bool prepare) -{ - GYamlNode *result; /* Trouvaille unique à renvoyer*/ - - result = g_yaml_node_find_one_by_path(tree->root, path, prepare); - - return result; - -} diff --git a/plugins/yaml/tree.h b/plugins/yaml/tree.h deleted file mode 100644 index bfe034a..0000000 --- a/plugins/yaml/tree.h +++ /dev/null @@ -1,69 +0,0 @@ - -/* Chrysalide - Outil d'analyse de fichiers binaires - * tree.h - prototypes pour une ligne de contenu Yaml - * - * Copyright (C) 2019 Cyrille Bagard - * - * This file is part of Chrysalide. - * - * Chrysalide is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * Chrysalide is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>. - */ - - -#ifndef PLUGINS_YAML_TREE_H -#define PLUGINS_YAML_TREE_H - - -#include <glib-object.h> -#include <stdbool.h> - - -#include "line.h" -#include "node.h" - - - -#define G_TYPE_YAML_TREE g_yaml_tree_get_type() -#define G_YAML_TREE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_TREE, GYamlTree)) -#define G_IS_YAML_TREE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_TREE)) -#define G_YAML_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_TREE, GYamlTreeClass)) -#define G_IS_YAML_TREE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_TREE)) -#define G_YAML_TREE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_TREE, GYamlTreeClass)) - - -/* Arborescence de lignes au format Yaml (instance) */ -typedef struct _GYamlTree GYamlTree; - -/* Arborescence de lignes au format Yaml (classe) */ -typedef struct _GYamlTreeClass GYamlTreeClass; - - -/* Indique le type défini pour une arborescence de lignes au format Yaml. */ -GType g_yaml_tree_get_type(void); - -/* Construit une arborescence à partir de lignes Yaml. */ -GYamlTree *g_yaml_tree_new(GYamlLine **, size_t); - -/* Fournit le noeud constituant la racine d'arborescence Yaml. */ -GYamlNode *g_yaml_tree_get_root(const GYamlTree *); - -/* Recherche les noeuds correspondant à un chemin. */ -void g_yaml_tree_find_by_path(const GYamlTree *, const char *, bool, GYamlNode ***, size_t *); - -/* Recherche l'unique noeud correspondant à un chemin. */ -GYamlNode *g_yaml_tree_find_one_by_path(GYamlTree *, const char *, bool); - - - -#endif /* PLUGINS_YAML_TREE_H */ |