From 33b5dc9af0404eabeb0e60245ab1ca1dc3713a17 Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 16 Jun 2019 22:20:46 +0200 Subject: Added support for Yaml content. --- configure.ac | 2 + plugins/Makefile.am | 3 +- plugins/pychrysalide/helpers.h | 3 + plugins/yaml/Makefile.am | 53 +++++ plugins/yaml/core.c | 77 +++++++ plugins/yaml/core.h | 38 ++++ plugins/yaml/line.c | 406 +++++++++++++++++++++++++++++++++++++ plugins/yaml/line.h | 71 +++++++ plugins/yaml/node.c | 335 +++++++++++++++++++++++++++++++ plugins/yaml/node.h | 71 +++++++ plugins/yaml/python/Makefile.am | 22 ++ plugins/yaml/python/line.c | 430 ++++++++++++++++++++++++++++++++++++++++ plugins/yaml/python/line.h | 45 +++++ plugins/yaml/python/module.c | 120 +++++++++++ plugins/yaml/python/module.h | 41 ++++ plugins/yaml/python/node.c | 363 +++++++++++++++++++++++++++++++++ plugins/yaml/python/node.h | 45 +++++ plugins/yaml/python/reader.c | 375 +++++++++++++++++++++++++++++++++++ plugins/yaml/python/reader.h | 45 +++++ plugins/yaml/python/tree.c | 366 ++++++++++++++++++++++++++++++++++ plugins/yaml/python/tree.h | 45 +++++ plugins/yaml/reader.c | 373 ++++++++++++++++++++++++++++++++++ plugins/yaml/reader.h | 69 +++++++ plugins/yaml/tree.c | 383 +++++++++++++++++++++++++++++++++++ plugins/yaml/tree.h | 69 +++++++ tests/plugins/yamlrdr.py | 94 +++++++++ 26 files changed, 3943 insertions(+), 1 deletion(-) create mode 100644 plugins/yaml/Makefile.am create mode 100644 plugins/yaml/core.c create mode 100644 plugins/yaml/core.h create mode 100644 plugins/yaml/line.c create mode 100644 plugins/yaml/line.h create mode 100644 plugins/yaml/node.c create mode 100644 plugins/yaml/node.h create mode 100644 plugins/yaml/python/Makefile.am create mode 100644 plugins/yaml/python/line.c create mode 100644 plugins/yaml/python/line.h create mode 100644 plugins/yaml/python/module.c create mode 100644 plugins/yaml/python/module.h create mode 100644 plugins/yaml/python/node.c create mode 100644 plugins/yaml/python/node.h create mode 100644 plugins/yaml/python/reader.c create mode 100644 plugins/yaml/python/reader.h create mode 100644 plugins/yaml/python/tree.c create mode 100644 plugins/yaml/python/tree.h create mode 100644 plugins/yaml/reader.c create mode 100644 plugins/yaml/reader.h create mode 100644 plugins/yaml/tree.c create mode 100644 plugins/yaml/tree.h create mode 100644 tests/plugins/yamlrdr.py diff --git a/configure.ac b/configure.ac index 2935fad..e58a0d6 100644 --- a/configure.ac +++ b/configure.ac @@ -465,6 +465,8 @@ AC_CONFIG_FILES([Makefile plugins/readelf/Makefile plugins/readmc/Makefile plugins/ropgadgets/Makefile + plugins/yaml/Makefile + plugins/yaml/python/Makefile src/Makefile src/analysis/Makefile src/analysis/contents/Makefile diff --git a/plugins/Makefile.am b/plugins/Makefile.am index 52b0592..678e315 100644 --- a/plugins/Makefile.am +++ b/plugins/Makefile.am @@ -25,4 +25,5 @@ SUBDIRS = \ readdex \ readelf \ readmc \ - ropgadgets + ropgadgets \ + yaml diff --git a/plugins/pychrysalide/helpers.h b/plugins/pychrysalide/helpers.h index 8c7db0b..3bb457d 100644 --- a/plugins/pychrysalide/helpers.h +++ b/plugins/pychrysalide/helpers.h @@ -97,6 +97,9 @@ bool register_python_module_object(PyObject *, PyTypeObject *); closure \ } +#define PYTHON_IS_DEF_FULL(name, base, doc) \ + PYTHON_GETSET_DEF("is_" #name, base ## _is_ ## name, NULL, doc, NULL) + #define PYTHON_GET_DEF_FULL(name, base, doc) \ PYTHON_GETSET_DEF(#name, base ## _get_ ## name, NULL, doc, NULL) diff --git a/plugins/yaml/Makefile.am b/plugins/yaml/Makefile.am new file mode 100644 index 0000000..d7464b8 --- /dev/null +++ b/plugins/yaml/Makefile.am @@ -0,0 +1,53 @@ + +lib_LTLIBRARIES = libyaml.la + +libdir = $(pluginslibdir) + + +if BUILD_PYTHON3_BINDINGS + +PYTHON3_LIBADD = \ + python/libyamlpython.la + +if BUILD_DISCARD_LOCAL + +PYTHON3_LDFLAGS = -Wl,-rpath,$(pluginslibdir) \ + -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so + +else + +PYTHON3_LDFLAGS = -Wl,-rpath,$(abs_top_srcdir)/plugins/pychrysalide/.libs \ + -L$(top_srcdir)/plugins/pychrysalide/.libs -l:pychrysalide.so + +endif + +PYTHON3_SUBDIRS = python + +endif + + +libyaml_la_SOURCES = \ + core.h core.c \ + line.h line.c \ + node.h node.c \ + reader.h reader.c \ + tree.h tree.c + +libyaml_la_LIBADD = \ + $(PYTHON3_LIBADD) + +libyaml_la_LDFLAGS = \ + -L$(top_srcdir)/src/.libs -lchrysacore \ + $(PYTHON3_LDFLAGS) + + +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/core.c b/plugins/yaml/core.c new file mode 100644 index 0000000..8bcea05 --- /dev/null +++ b/plugins/yaml/core.c @@ -0,0 +1,77 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.c - lecture de contenus au format 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 . + */ + + +#include "core.h" + + +#include + + +#ifdef HAVE_PYTHON3_BINDINGS +# include "python/module.h" +#endif + + +#ifdef HAVE_PYTHON3_BINDINGS +# define PG_REQ RL("PyChrysalide") +#else +# define PG_REQ NO_REQ +#endif + + +DEFINE_CHRYSALIDE_PLUGIN("GYamlPlugin", "yaml", "Reader for Yaml contents", "0.1.0", + 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; + +#ifdef HAVE_PYTHON3_BINDINGS + + if (result) + result = add_yaml_module_to_python_module(); + + if (result) + result = populate_yaml_module(); + +#endif + + return result; + +} diff --git a/plugins/yaml/core.h b/plugins/yaml/core.h new file mode 100644 index 0000000..a46dbe7 --- /dev/null +++ b/plugins/yaml/core.h @@ -0,0 +1,38 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * core.h - prototypes pour la lecture de contenus au format 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 . + */ + + +#ifndef _PLUGINS_YAML_CORE_H +#define _PLUGINS_YAML_CORE_H + + +#include +#include + + + +/* Prend acte du chargement du greffon. */ +G_MODULE_EXPORT bool chrysalide_plugin_init(GPluginModule *); + + + +#endif /* _PLUGINS_YAML_CORE_H */ diff --git a/plugins/yaml/line.c b/plugins/yaml/line.c new file mode 100644 index 0000000..cd993ee --- /dev/null +++ b/plugins/yaml/line.c @@ -0,0 +1,406 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * line.c - 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 . + */ + + +#include "line.h" + + +#include +#include + + +#include + + + +/* 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 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 *); + +/* Supprime toutes les références externes. */ +static void g_yaml_line_dispose(GYamlLine *); + +/* Procède à la libération totale de la mémoire. */ +static void g_yaml_line_finalize(GYamlLine *); + + + +/* Indique le type défini pour une ligne de données au format Yaml. */ +G_DEFINE_TYPE(GYamlLine, g_yaml_line, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des lignes de contenu Yaml. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_line_class_init(GYamlLineClass *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; + +} + + +/****************************************************************************** +* * +* Paramètres : line = instance à initialiser. * +* * +* Description : Initialise une instance de ligne de contenu Yaml. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_line_init(GYamlLine *line) +{ + line->raw = NULL; + line->number = -1; + + line->indent = 0; + line->is_list_item = false; + + line->payload = NULL; + line->key = NULL; + line->value = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : line = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_line_dispose(GYamlLine *line) +{ + G_OBJECT_CLASS(g_yaml_line_parent_class)->dispose(G_OBJECT(line)); + +} + + +/****************************************************************************** +* * +* Paramètres : line = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_line_finalize(GYamlLine *line) +{ + if (line->raw != NULL) + free(line->raw); + + if (line->key != NULL) + free(line->key); + + if (line->value != NULL) + free(line->value); + + G_OBJECT_CLASS(g_yaml_line_parent_class)->finalize(G_OBJECT(line)); + +} + + +/****************************************************************************** +* * +* Paramètres : raw = contenu brut d'une ligne au format Yaml. * +* number = indice associé à la ligne. * +* * +* Description : Met en place un gestionnaire pour ligne au format Yaml. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlLine *g_yaml_line_new(const char *raw, size_t number) +{ + GYamlLine *result; /* Structure à retourner */ + char *iter; /* Boucle de parcours */ + bool string_content[2]; /* Ouvertures de chaînes */ + bool escape; /* Echappement de marquant */ + + result = g_object_new(G_TYPE_YAML_LINE, NULL); + + result->raw = strdup(raw); + result->number = number; + + /* Indentation */ + + for (iter = result->raw; *iter != '\0'; iter++) + { + if (*iter != ' ' && *iter != '-') + break; + + result->indent++; + + if (*iter == '-') + { + if (result->is_list_item) + goto format_error; + + result->is_list_item = true; + + } + + } + + result->payload = iter; + + /* Eventuel couple clef/valeur */ + + string_content[0] = false; + string_content[1] = false; + + for (; *iter != '\0'; iter++) + { + if (*iter == '\'' && !string_content[1]) + { + if (iter == result->payload) + escape = false; + + else + escape = *(iter - 1) == '\''; + + if (!escape) + string_content[0] = !string_content[0]; + + } + + else if (*iter == '"' && !string_content[0]) + { + if (iter == result->payload) + escape = false; + + else + escape = *(iter - 1) == '\\'; + + if (!escape) + string_content[1] = !string_content[1]; + + } + + else if (!string_content[0] && !string_content[1]) + { + + if (*iter == ':') + break; + + + } + + } + + if (*iter != '\0') + { + result->key = strndup(result->payload, iter - result->payload); + + for (iter++; *iter != '\0'; iter++) + if (*iter != ' ') + break; + + if (*iter != '\0') + result->value = strdup(iter); + + } + + return result; + + format_error: + + log_variadic_message(LMT_ERROR, "Yaml format error at line %zu", number); + + g_object_unref(G_OBJECT(result)); + + return NULL; + +} + + +/****************************************************************************** +* * +* 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 = line->indent; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne au format Yaml à consulter. * +* * +* Description : Indique si la ligne représente un élément de liste. * +* * +* Retour : Statut de l'état lié à une liste d'éléments. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_yaml_line_is_list_item(const GYamlLine *line) +{ + bool result; /* Statut à retourner */ + + result = line->is_list_item; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne au format Yaml à consulter. * +* * +* Description : Fournit la charge utile associée à une ligne Yaml. * +* * +* Retour : Contenu sous forme de chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_yaml_line_get_payload(const GYamlLine *line) +{ + const char *result; /* Valeur à retourner */ + + result = line->payload; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne au format Yaml à consulter. * +* * +* Description : Fournit la clef associée à une ligne Yaml si elle existe. * +* * +* Retour : Clef sous forme de chaîne de caractères ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_yaml_line_get_key(const GYamlLine *line) +{ + char *result; /* Valeur à retourner */ + + result = line->key; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : line = ligne au format Yaml à consulter. * +* * +* Description : Fournit la valeur associée à une ligne Yaml si elle existe. * +* * +* Retour : Valeur sous forme de chaîne de caractères ou NULL. * +* * +* Remarques : - * +* * +******************************************************************************/ + +const char *g_yaml_line_get_value(const GYamlLine *line) +{ + char *result; /* Valeur à retourner */ + + result = line->value; + + return result; + +} diff --git a/plugins/yaml/line.h b/plugins/yaml/line.h new file mode 100644 index 0000000..b959272 --- /dev/null +++ b/plugins/yaml/line.h @@ -0,0 +1,71 @@ + +/* 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 . + */ + + +#ifndef PLUGINS_YAML_LINE_H +#define PLUGINS_YAML_LINE_H + + +#include +#include + + + +#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 *); + + + +#endif /* PLUGINS_YAML_LINE_H */ diff --git a/plugins/yaml/node.c b/plugins/yaml/node.c new file mode 100644 index 0000000..b0229c0 --- /dev/null +++ b/plugins/yaml/node.c @@ -0,0 +1,335 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node.c - 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 . + */ + + +#include "node.h" + + +#include +#include + + + +/* Noeud d'une arborescence au format Yaml (instance) */ +struct _GYamlNode +{ + GObject parent; /* A laisser en premier */ + + GYamlLine *key; /* Clef principale du noeud */ + + GYamlNode **children; /* Sous-noeuds intégrés */ + size_t count; /* Nombre de ces enfants */ + +}; + +/* Noeud d'une arborescence au format Yaml (classe) */ +struct _GYamlNodeClass +{ + GObjectClass parent; /* A laisser en premier */ + +}; + + +/* Initialise la classe des noeuds d'arborescence Yaml. */ +static void g_yaml_node_class_init(GYamlNodeClass *); + +/* Initialise une instance de noeud d'arborescence Yaml. */ +static void g_yaml_node_init(GYamlNode *); + +/* Supprime toutes les références externes. */ +static void g_yaml_node_dispose(GYamlNode *); + +/* Procède à la libération totale de la mémoire. */ +static void g_yaml_node_finalize(GYamlNode *); + + + +/* Indique le type défini pour un noeud d'arborescence Yaml. */ +G_DEFINE_TYPE(GYamlNode, g_yaml_node, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des noeuds d'arborescence Yaml. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_node_class_init(GYamlNodeClass *klass) +{ + GObjectClass *object; /* Autre version de la classe */ + + object = G_OBJECT_CLASS(klass); + + object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_node_dispose; + object->finalize = (GObjectFinalizeFunc)g_yaml_node_finalize; + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance à initialiser. * +* * +* Description : Initialise une instance de noeud d'arborescence Yaml. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_node_init(GYamlNode *node) +{ + node->key = NULL; + + node->children = NULL; + node->count = 0; + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_node_dispose(GYamlNode *node) +{ + size_t i; /* Boucle de parcours */ + + g_clear_object(&node->key); + + for (i = 0; i < node->count; i++) + g_clear_object(&node->children[i]); + + G_OBJECT_CLASS(g_yaml_node_parent_class)->dispose(G_OBJECT(node)); + +} + + +/****************************************************************************** +* * +* Paramètres : node = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_node_finalize(GYamlNode *node) +{ + if (node->children != NULL) + free(node->children); + + G_OBJECT_CLASS(g_yaml_node_parent_class)->finalize(G_OBJECT(node)); + +} + + +/****************************************************************************** +* * +* Paramètres : key = line Yaml représentant la clef du futur noeud. * +* * +* Description : Construit un noeud d'arborescence Yaml. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlNode *g_yaml_node_new(GYamlLine *key) +{ + GYamlNode *result; /* Structure à retourner */ + + result = g_object_new(G_TYPE_YAML_NODE, NULL); + + result->key = key; + g_object_ref(G_OBJECT(key)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* * +* Description : Fournit la ligne principale associée à un noeud. * +* * +* Retour : Ligne Yaml à l'origine du noeud. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node) +{ + GYamlLine *result; /* Ligne d'origine à renvoyer */ + + result = node->key; + + g_object_ref(G_OBJECT(result)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud d'arborescence Yaml à compléter. * +* child = noeud à rattacher. * +* * +* Description : Ajoute un noeud à un noeud d'une arborescence Yaml. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_yaml_node_add_child(GYamlNode *node, GYamlNode *child) +{ + node->children = realloc(node->children, ++node->count * sizeof(GYamlNode *)); + + node->children[node->count - 1] = child; + g_object_ref_sink(G_OBJECT(child)); + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* count = taille de la liste constituée. [OUT] * +* * +* Description : Fournit la liste des noeuds intégrés dans un noeud Yaml. * +* * +* Retour : Enfants d'un noeud issu d'une arborescence Yaml. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlNode **g_yaml_node_get_children(const GYamlNode *node, size_t *count) +{ + GYamlNode **result; /* Liste à retourner */ + size_t i; /* Boucle de parcours */ + + *count = node->count; + + result = malloc(*count * sizeof(GYamlNode *)); + + for (i = 0; i < *count; i++) + { + result[i] = node->children[i]; + g_object_ref(G_OBJECT(result[i])); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : node = noeud d'arborescence Yaml à consulter. * +* path = chemin d'accès à parcourir. * +* * +* Description : Recherche le noeud correspondant à un chemin. * +* * +* Retour : Eventuel noeud trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlNode *g_yaml_node_find_node_by_path(GYamlNode *node, const char *path) +{ + GYamlNode *result; /* Trouvaille à retourner */ + char *next; /* Prochaine partie du chemin */ + size_t cmplen; /* Etendue de la comparaison */ + size_t i; /* Boucle de parcours */ + GYamlLine *line; /* Ligne Yaml d'un enfant */ + const char *key; /* Clef d'un noeud */ + int ret; /* Bilan d'une comparaison */ + + result = NULL; + + if (path[0] == '\0') + result = node; + + else if (path[0] == '/') + { + next = strchr(path + 1, '/'); + + cmplen = (next == NULL ? strlen(path + 1) : next - path - 1); + + if (cmplen == 0) + result = node; + + for (i = 0; i < node->count && result == NULL; i++) + { + line = g_yaml_node_get_yaml_line(node->children[i]); + + key = g_yaml_line_get_key(line); + + ret = strncmp(path + 1, key, cmplen); + + if (ret == 0) + { + if (next != NULL) + result = g_yaml_node_find_node_by_path(node->children[i], next); + + else + result = node->children[i]; + + } + + } + + } + + if (result != NULL) + g_object_ref(G_OBJECT(result)); + + return result; + +} diff --git a/plugins/yaml/node.h b/plugins/yaml/node.h new file mode 100644 index 0000000..582fa58 --- /dev/null +++ b/plugins/yaml/node.h @@ -0,0 +1,71 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node.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 . + */ + + +#ifndef PLUGINS_YAML_NODE_H +#define PLUGINS_YAML_NODE_H + + +#include +#include + + +#include "line.h" + + + +#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)) +#define G_IS_YAML_NODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_NODE)) +#define G_YAML_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_NODE, GYamlNodeClass)) +#define G_IS_YAML_NODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_NODE)) +#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) */ +typedef struct _GYamlNode GYamlNode; + +/* 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); + +/* Construit un noeud d'arborescence Yaml. */ +GYamlNode *g_yaml_node_new(GYamlLine *); + +/* Fournit la ligne principale associée à un noeud. */ +GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *); + +/* Ajoute un noeud à un noeud d'une arborescence Yaml. */ +void g_yaml_node_add_child(GYamlNode *, GYamlNode *); + +/* Fournit la liste des noeuds intégrés dans un noeud Yaml. */ +GYamlNode **g_yaml_node_get_children(const GYamlNode *, size_t *); + +/* Recherche le noeud correspondant à un chemin. */ +GYamlNode *g_yaml_node_find_node_by_path(GYamlNode *, const char *); + + + +#endif /* PLUGINS_YAML_NODE_H */ diff --git a/plugins/yaml/python/Makefile.am b/plugins/yaml/python/Makefile.am new file mode 100644 index 0000000..8a8d960 --- /dev/null +++ b/plugins/yaml/python/Makefile.am @@ -0,0 +1,22 @@ + +noinst_LTLIBRARIES = libyamlpython.la + +libyamlpython_la_SOURCES = \ + line.h line.c \ + module.h module.c \ + node.h node.c \ + reader.h reader.c \ + tree.h tree.c + +libyamlpython_la_LDFLAGS = + + +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/line.c b/plugins/yaml/python/line.c new file mode 100644 index 0000000..11898d2 --- /dev/null +++ b/plugins/yaml/python/line.c @@ -0,0 +1,430 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * line.c - équivalent Python du fichier "plugins/yaml/line.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 "line.h" + + +#include + + +#include + + +#include "../line.h" + + + +/* Crée un nouvel objet Python de type 'YamlLine'. */ +static PyObject *py_yaml_line_new(PyTypeObject *, PyObject *, PyObject *); + +/* Fournit la taille de l'indentation d'une ligne Yaml. */ +static PyObject *py_yaml_line_get_indent(PyObject *, void *); + +/* Indique si la ligne représente un élément de liste. */ +static PyObject *py_yaml_line_is_list_item(PyObject *, void *); + +/* Fournit la charge utile associée à une ligne Yaml. */ +static PyObject *py_yaml_line_get_payload(PyObject *, void *); + +/* Fournit la clef associée à une ligne Yaml si elle existe. */ +static PyObject *py_yaml_line_get_key(PyObject *, void *); + +/* Fournit la valeur associée à une ligne Yaml si elle existe. */ +static PyObject *py_yaml_line_get_value(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 'YamlLine'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_line_new(PyTypeObject *type, 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); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la taille de l'indentation d'une ligne Yaml. * +* * +* Retour : Taille de l'indentation rencontrée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_line_get_indent(PyObject *self, 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." \ +) + + line = G_YAML_LINE(pygobject_get(self)); + + indent = g_yaml_line_count_indent(line); + + result = PyLong_FromSize_t(indent); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Indique si la ligne représente un élément de liste. * +* * +* Retour : Statut de l'état lié à une liste d'éléments. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_line_is_list_item(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." \ +) + + line = G_YAML_LINE(pygobject_get(self)); + + status = g_yaml_line_is_list_item(line); + + 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 charge utile associée à une ligne Yaml. * +* * +* Retour : Contenu sous forme de chaîne de caractères. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_line_get_payload(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." \ +) + + line = G_YAML_LINE(pygobject_get(self)); + + payload = g_yaml_line_get_payload(line); + + result = PyUnicode_FromString(payload); + + return result; + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Retour : Clef sous forme de chaîne de caractères ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_line_get_key(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)); + + key = g_yaml_line_get_key(line); + + if (key == NULL) + { + result = Py_None; + Py_INCREF(result); + } + + else + result = PyUnicode_FromString(key); + + return result; + +} + + +/****************************************************************************** +* * +* 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. * +* * +* Retour : Valeur sous forme de chaîne de caractères ou None. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_line_get_value(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." \ +) + + line = G_YAML_LINE(pygobject_get(self)); + + value = g_yaml_line_get_value(line); + + if (value == NULL) + { + result = Py_None; + Py_INCREF(result); + } + + else + result = PyUnicode_FromString(value); + + 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_line_type(void) +{ + static PyMethodDef py_yaml_line_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, + { NULL } + }; + + static PyTypeObject py_yaml_line_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.yaml.YamlLine", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = YAML_LINE_DOC, + + .tp_methods = py_yaml_line_methods, + .tp_getset = py_yaml_line_getseters, + .tp_new = py_yaml_line_new + + }; + + return &py_yaml_line_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlLine. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_yaml_line(PyObject *module) +{ + PyTypeObject *type; /* Type Python 'YamlLine' */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_yaml_line_type(); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_YAML_LINE, 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 ligne de données au format Yaml. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_yaml_line(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_line_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 line"); + break; + + case 1: + *((GYamlLine **)dst) = G_YAML_LINE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/yaml/python/line.h b/plugins/yaml/python/line.h new file mode 100644 index 0000000..00dcbd9 --- /dev/null +++ b/plugins/yaml/python/line.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * line.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/line.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_YAML_PYTHON_LINE_H +#define _PLUGINS_YAML_PYTHON_LINE_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_yaml_line_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlLine'. */ +bool register_python_yaml_line(PyObject *); + +/* Tente de convertir en ligne de données au format Yaml. */ +int convert_to_yaml_line(PyObject *, void *); + + + +#endif /* _PLUGINS_YAML_PYTHON_LINE_H */ diff --git a/plugins/yaml/python/module.c b/plugins/yaml/python/module.c new file mode 100644 index 0000000..542a551 --- /dev/null +++ b/plugins/yaml/python/module.c @@ -0,0 +1,120 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.c - intégration du répertoire yaml 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 +#include + + +#include +#include + + +#include "line.h" +#include "node.h" +#include "reader.h" +#include "tree.h" + + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Ajoute le module 'plugins.yaml' au module Python. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool add_yaml_module_to_python_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *super; /* Module à compléter */ + PyObject *module; /* Sous-module mis en place */ + +#define PYCHRYSALIDE_PLUGINS_YAML_DOC \ + "yaml is a module providing access to Yaml content." + + static PyModuleDef py_chrysalide_yaml_module = { + + .m_base = PyModuleDef_HEAD_INIT, + + .m_name = "pychrysalide.plugins.yaml", + .m_doc = PYCHRYSALIDE_PLUGINS_YAML_DOC, + + .m_size = -1, + + }; + + result = false; + + super = get_access_to_python_module("pychrysalide.plugins"); + + module = build_python_module(super, &py_chrysalide_yaml_module); + + result = (module != NULL); + + assert(result); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : - * +* * +* Description : Intègre les objets du module 'plugins.yaml'. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool populate_yaml_module(void) +{ + bool result; /* Bilan à retourner */ + PyObject *module; /* Module à recompléter */ + + result = true; + + module = get_access_to_python_module("pychrysalide.plugins.yaml"); + + if (result) result = register_python_yaml_line(module); + if (result) result = register_python_yaml_node(module); + if (result) result = register_python_yaml_reader(module); + if (result) result = register_python_yaml_tree(module); + + assert(result); + + return result; + +} diff --git a/plugins/yaml/python/module.h b/plugins/yaml/python/module.h new file mode 100644 index 0000000..c4782f7 --- /dev/null +++ b/plugins/yaml/python/module.h @@ -0,0 +1,41 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * module.h - prototypes pour l'intégration du répertoire yaml 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_YAML_PYTHON_MODULE_H +#define _PLUGINS_YAML_PYTHON_MODULE_H + + +#include + + + +/* Ajoute le module 'plugins.yaml' au module Python. */ +bool add_yaml_module_to_python_module(void); + +/* Intègre les objets du module 'plugins.yaml'. */ +bool populate_yaml_module(void); + + + +#endif /* _PLUGINS_YAML_PYTHON_MODULE_H */ diff --git a/plugins/yaml/python/node.c b/plugins/yaml/python/node.c new file mode 100644 index 0000000..d1aabee --- /dev/null +++ b/plugins/yaml/python/node.c @@ -0,0 +1,363 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * node.c - équivalent Python du fichier "plugins/yaml/node.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 "node.h" + + +#include + + +#include + + +#include "line.h" +#include "../node.h" + + + +/* Crée un nouvel objet Python de type 'YamlNode'. */ +static PyObject *py_yaml_node_new(PyTypeObject *, PyObject *, PyObject *); + +/* Recherche le noeud correspondant à un chemin. */ +static PyObject *py_yaml_node_find_node_by_path(PyObject *, PyObject *); + +/* Fournit la ligne principale associée à un noeud. */ +static PyObject *py_yaml_node_get_yaml_line(PyObject *, void *); + +/* Fournit la liste des noeuds intégrés dans un noeud Yaml. */ +static PyObject *py_yaml_node_get_children(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 'YamlNode'. * +* * +* Retour : Instance Python mise en place. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_node_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *result; /* Instance à retourner */ + GYamlLine *key; /* Ligne principale du noeud */ + int ret; /* Bilan de lecture des args. */ + GYamlNode *node; /* Création GLib à transmettre */ + +#define YAML_NODE_DOC \ + "YamlNode handle a node in a Yaml tree.\n" \ + "\n" \ + "Instances can be created using the following constructor:\n" \ + "\n" \ + " YamlNode(key)\n" \ + "\n" \ + "Where key is the main Yaml line for the node." + + ret = PyArg_ParseTuple(args, "O&", &convert_to_yaml_line, &key); + if (!ret) return NULL; + + node = g_yaml_node_new(key); + + g_object_ref_sink(G_OBJECT(node)); + result = pygobject_new(G_OBJECT(node)); + g_object_unref(node); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = variable non utilisée ici. * +* args = arguments fournis à l'appel. * +* * +* Description : Recherche le noeud correspondant à un chemin. * +* * +* Retour : Eventuel noeud trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_node_find_node_by_path(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + const char *path; /* Chemin d'accès à traiter */ + int ret; /* Bilan de lecture des args. */ + GYamlNode *node; /* Version GLib du type */ + GYamlNode *found; /* Création GLib à transmettre */ + +#define YAML_NODE_FIND_BY_PATH PYTHON_METHOD_DEF \ +( \ + find_node_by_path, "path", \ + METH_VARARGS, py_yaml_node, \ + "Find a child node in a Yaml node by its path.\n" \ + "\n" \ + "Paths are node keys separated by '/', such as '/my/path/to/node'." \ +) + + ret = PyArg_ParseTuple(args, "s", &path); + if (!ret) return NULL; + + node = G_YAML_NODE(pygobject_get(self)); + + found = g_yaml_node_find_node_by_path(node, path); + + if (found == NULL) + { + result = Py_None; + Py_INCREF(result); + } + + else + { + result = pygobject_new(G_OBJECT(found)); + g_object_unref(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 type */ + 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); + + result = pygobject_new(G_OBJECT(line)); + + g_object_unref(G_OBJECT(line)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la liste des noeuds intégrés dans un noeud Yaml. * +* * +* Retour : Enfants d'un noeud issu d'une arborescence Yaml. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_node_get_children(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GYamlNode *node; /* Version GLib du type */ + size_t count; /* Quantité de noeuds à traiter*/ + GYamlNode **nodes; /* Liste des noeuds à la racine*/ + size_t i; /* Boucle de parcours */ +#ifndef NDEBUG + int ret; /* Bilan d'une insertion */ +#endif + +#define YAML_NODE_CHILDREN_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + children, py_yaml_node, \ + "List of nodes which are children of the current node." \ +) + + node = G_YAML_NODE(pygobject_get(self)); + + nodes = g_yaml_node_get_children(node, &count); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { +#ifndef NDEBUG + ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i]))); + assert(ret == 0); +#else + PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i]))); +#endif + + g_object_unref(G_OBJECT(nodes[i])); + + } + + free(nodes); + + 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_node_type(void) +{ + static PyMethodDef py_yaml_node_methods[] = { + YAML_NODE_FIND_BY_PATH, + { NULL } + }; + + static PyGetSetDef py_yaml_node_getseters[] = { + YAML_NODE_YAML_LINE_ATTRIB, + YAML_NODE_CHILDREN_ATTRIB, + { NULL } + }; + + static PyTypeObject py_yaml_node_type = { + + PyVarObject_HEAD_INIT(NULL, 0) + + .tp_name = "pychrysalide.plugins.yaml.YamlNode", + .tp_basicsize = sizeof(PyGObject), + + .tp_flags = Py_TPFLAGS_DEFAULT, + + .tp_doc = YAML_NODE_DOC, + + .tp_methods = py_yaml_node_methods, + .tp_getset = py_yaml_node_getseters, + .tp_new = py_yaml_node_new + + }; + + return &py_yaml_node_type; + +} + + +/****************************************************************************** +* * +* Paramètres : module = module dont la définition est à compléter. * +* * +* Description : Prend en charge l'objet 'pychrysalide.plugins.....YamlNode. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool register_python_yaml_node(PyObject *module) +{ + PyTypeObject *type; /* Type Python 'YamlNode' */ + PyObject *dict; /* Dictionnaire du module */ + + type = get_python_yaml_node_type(); + + dict = PyModule_GetDict(module); + + if (!register_class_for_pygobject(dict, G_TYPE_YAML_NODE, 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 noeud d'arborescence de format Yaml. * +* * +* Retour : Bilan de l'opération, voire indications supplémentaires. * +* * +* Remarques : - * +* * +******************************************************************************/ + +int convert_to_yaml_node(PyObject *arg, void *dst) +{ + int result; /* Bilan à retourner */ + + result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_node_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 node"); + break; + + case 1: + *((GYamlNode **)dst) = G_YAML_NODE(pygobject_get(arg)); + break; + + default: + assert(false); + break; + + } + + return result; + +} diff --git a/plugins/yaml/python/node.h b/plugins/yaml/python/node.h new file mode 100644 index 0000000..dc3686b --- /dev/null +++ b/plugins/yaml/python/node.h @@ -0,0 +1,45 @@ + +/* 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 + * + * 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_NODE_H +#define _PLUGINS_YAML_PYTHON_NODE_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_yaml_node_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlNode'. */ +bool register_python_yaml_node(PyObject *); + +/* Tente de convertir en noeud d'arborescence de format Yaml. */ +int convert_to_yaml_node(PyObject *, void *); + + + +#endif /* _PLUGINS_YAML_PYTHON_NODE_H */ diff --git a/plugins/yaml/python/reader.c b/plugins/yaml/python/reader.c new file mode 100644 index 0000000..43db6bb --- /dev/null +++ b/plugins/yaml/python/reader.c @@ -0,0 +1,375 @@ + +/* 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 + + +#include + + +#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 PYTHON_METHOD_DEF \ +( \ + new_from_content, "content", \ + METH_STATIC | METH_VARARGS, py_yaml_reader, \ + "Load a Yaml content." \ +) + + 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 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])); + + } + + 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); + + 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, + YAML_READER_NEW_FROM_PATH, + { 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/reader.h b/plugins/yaml/python/reader.h new file mode 100644 index 0000000..19d238b --- /dev/null +++ b/plugins/yaml/python/reader.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * reader.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/reader.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_YAML_PYTHON_READER_H +#define _PLUGINS_YAML_PYTHON_READER_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_yaml_reader_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlReader'. */ +bool register_python_yaml_reader(PyObject *); + +/* Tente de convertir en lecteur de données au format Yaml. */ +int convert_to_yaml_reader(PyObject *, void *); + + + +#endif /* _PLUGINS_YAML_PYTHON_READER_H */ diff --git a/plugins/yaml/python/tree.c b/plugins/yaml/python/tree.c new file mode 100644 index 0000000..9e1a2a3 --- /dev/null +++ b/plugins/yaml/python/tree.c @@ -0,0 +1,366 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tree.c - équivalent Python du fichier "plugins/yaml/tree.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 "tree.h" + + +#include + + +#include +#include + + +#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 le noeud correspondant à un chemin. */ +static PyObject *py_yaml_tree_find_node_by_path(PyObject *, PyObject *); + +/* Fournit la liste des premiers noeuds de l'arborescence Yaml. */ +static PyObject *py_yaml_tree_get_root_nodes(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 */ + Py_ssize_t indent; /* Indice de ligne associée */ + 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 */ + size_t i; /* Boucle de parcours #1 */ + PyObject *item; /* Elément de la liste fournie */ + size_t k; /* Boucle de parcours #2 */ + GYamlTree *tree; /* Création GLib à transmettre */ + +#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(indent, lines)" \ + "\n" \ + "Where indent provides the length of a single level of indentation" \ + " and lines are a tuple of Yaml lines used to built the tree." + + ret = PyArg_ParseTuple(args, "nO!", &indent, &PyTuple_Type, &tuple); + if (!ret) return NULL; + + count = PyTuple_Size(tuple); + + lines = (GYamlLine **)malloc(count * sizeof(GYamlLine *)); + + 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(indent, 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 le noeud correspondant à un chemin. * +* * +* Retour : Eventuel noeud trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_tree_find_node_by_path(PyObject *self, PyObject *args) +{ + PyObject *result; /* Instance à retourner */ + 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_BY_PATH PYTHON_METHOD_DEF \ +( \ + find_node_by_path, "path", \ + METH_VARARGS, py_yaml_tree, \ + "Find a node in a Yaml tree by its path.\n" \ + "\n" \ + "Paths are node keys separated by '/', such as '/my/path/to/node'." \ +) + + ret = PyArg_ParseTuple(args, "s", &path); + if (!ret) return NULL; + + tree = G_YAML_TREE(pygobject_get(self)); + + found = g_yaml_tree_find_node_by_path(tree, path); + + if (found == NULL) + { + result = Py_None; + Py_INCREF(result); + } + + else + { + result = pygobject_new(G_OBJECT(found)); + g_object_unref(found); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : self = objet Python concerné par l'appel. * +* closure = non utilisé ici. * +* * +* Description : Fournit la liste des premiers noeuds de l'arborescence Yaml. * +* * +* Retour : Noeuds constituant les racines de l'arborescence. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static PyObject *py_yaml_tree_get_root_nodes(PyObject *self, void *closure) +{ + PyObject *result; /* Résultat à retourner */ + GYamlTree *tree; /* Version GLib du type */ + size_t count; /* Quantité de noeuds à traiter*/ + GYamlNode **nodes; /* Liste des noeuds à la racine*/ + size_t i; /* Boucle de parcours */ +#ifndef NDEBUG + int ret; /* Bilan d'une insertion */ +#endif + +#define YAML_TREE_ROOT_NODES_ATTRIB PYTHON_GET_DEF_FULL \ +( \ + root_nodes, py_yaml_tree, \ + "List of Yaml nodes which are the roots of all tree nodes." \ +) + + tree = G_YAML_TREE(pygobject_get(self)); + + nodes = g_yaml_tree_get_root_nodes(tree, &count); + + result = PyTuple_New(count); + + for (i = 0; i < count; i++) + { +#ifndef NDEBUG + ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i]))); + assert(ret == 0); +#else + PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(nodes[i]))); +#endif + + g_object_unref(G_OBJECT(nodes[i])); + + } + + free(nodes); + + 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, + { NULL } + }; + + static PyGetSetDef py_yaml_tree_getseters[] = { + YAML_TREE_ROOT_NODES_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/python/tree.h b/plugins/yaml/python/tree.h new file mode 100644 index 0000000..df9d5b8 --- /dev/null +++ b/plugins/yaml/python/tree.h @@ -0,0 +1,45 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tree.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/tree.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_YAML_PYTHON_TREE_H +#define _PLUGINS_YAML_PYTHON_TREE_H + + +#include +#include + + + +/* Fournit un accès à une définition de type à diffuser. */ +PyTypeObject *get_python_yaml_tree_type(void); + +/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlTree'. */ +bool register_python_yaml_tree(PyObject *); + +/* Tente de convertir en arborescence de lignes au format Yaml. */ +int convert_to_yaml_tree(PyObject *, void *); + + + +#endif /* _PLUGINS_YAML_PYTHON_TREE_H */ diff --git a/plugins/yaml/reader.c b/plugins/yaml/reader.c new file mode 100644 index 0000000..02e1aa9 --- /dev/null +++ b/plugins/yaml/reader.c @@ -0,0 +1,373 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * reader.c - 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 . + */ + + +#include "reader.h" + + +#include +#include +#include + + +#include "line.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 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 *); + +/* Supprime toutes les références externes. */ +static void g_yaml_reader_dispose(GYamlReader *); + +/* Procède à la libération totale de la mémoire. */ +static void g_yaml_reader_finalize(GYamlReader *); + + + +/* Indique le type défini pour un lecteur de contenu Yaml. */ +G_DEFINE_TYPE(GYamlReader, g_yaml_reader, G_TYPE_OBJECT); + + +/****************************************************************************** +* * +* Paramètres : klass = classe à initialiser. * +* * +* Description : Initialise la classe des lecteurs de contenus Yaml. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_reader_class_init(GYamlReaderClass *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; + +} + + +/****************************************************************************** +* * +* Paramètres : reader = instance à initialiser. * +* * +* Description : Initialise une instance de lecteur de contenu Yaml. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_reader_init(GYamlReader *reader) +{ + reader->lines = NULL; + reader->count = 0; + + reader->tree = NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : reader = instance d'objet GLib à traiter. * +* * +* Description : Supprime toutes les références externes. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_reader_dispose(GYamlReader *reader) +{ + 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)); + +} + + +/****************************************************************************** +* * +* Paramètres : reader = instance d'objet GLib à traiter. * +* * +* Description : Procède à la libération totale de la mémoire. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +static void g_yaml_reader_finalize(GYamlReader *reader) +{ + if (reader->lines != NULL) + free(reader->lines); + + G_OBJECT_CLASS(g_yaml_reader_parent_class)->finalize(G_OBJECT(reader)); + +} + + +/****************************************************************************** +* * +* Paramètres : content = données brutes au format Yaml à charger. * +* length = quantité de ces données. * +* * +* Description : Crée un lecteur pour contenu au format Yaml. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length) +{ + GYamlReader *result; /* Structure à retourner */ + char *dumped; /* Contenu manipulable */ + size_t level; /* Niveau unique d'indentation */ + 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); + + level = 0; + + for (iter = dumped, saved = strchr(iter, '\n'), number = 0; + *iter != '\0'; + iter = ++saved, saved = strchr(iter, '\n'), number++) + { + *saved = '\0'; + + if (*iter == '\0') + continue; + + line = g_yaml_line_new(iter, number); + + if (line == NULL) + goto format_error; + + if (level == 0) + level = g_yaml_line_count_indent(line); + + result->lines = realloc(result->lines, ++result->count * sizeof(GYamlLine *)); + + g_object_ref_sink(G_OBJECT(line)); + result->lines[result->count - 1] = line; + + } + + free(dumped); + + result->tree = g_yaml_tree_new(level, result->lines, result->count); + g_object_ref_sink(G_OBJECT(result->tree)); + + return result; + + format_error: + + g_object_unref(G_OBJECT(result)); + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : path = chemin d'accès à un contenu à charger. * +* * +* Description : Crée un lecteur pour contenu au format Yaml. * +* * +* Retour : Instance mise en place ou NULL en cas d'échec. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlReader *g_yaml_reader_new_from_path(const char *path) +{ + 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; + + /* Ouverture du fichier */ + + scheme = g_uri_parse_scheme(path); + + if (scheme != NULL) + { + g_free(scheme); + file = g_file_new_for_uri(path); + } + + else + file = g_file_new_for_path(path); + + stream = g_file_read(file, NULL, NULL); + + if (stream == NULL) + goto no_content; + + /* Détermination de sa taille */ + + info = g_file_input_stream_query_info(stream, G_FILE_ATTRIBUTE_STANDARD_SIZE, NULL, NULL); + + if (info == NULL) + goto no_size_info; + + length = g_file_info_get_size(info); + + /* Lecture des données */ + + 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); + + read_error: + + free(content); + + no_size_info: + + g_object_unref(G_OBJECT(stream)); + + no_content: + + g_object_unref(G_OBJECT(file)); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : reader = lecteur de contenu Yaml à consulter. * +* count = taille de la liste constituée. [OUT] * +* * +* Description : Fournit la liste des lignes lues depuis un contenu Yaml. * +* * +* Retour : Liste de lignes correspondant au contenu Yaml lu. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlLine **g_yaml_reader_get_lines(const GYamlReader *reader, size_t *count) +{ + GYamlLine **result; /* Liste à retourner */ + size_t i; /* Boucle de parcours */ + + *count = reader->count; + + result = malloc(*count * sizeof(GYamlLine *)); + + for (i = 0; i < *count; i++) + { + result[i] = reader->lines[i]; + g_object_ref(result[i]); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : reader = lecteur de contenu Yaml à consulter. * +* * +* Description : Fournit l'arborescence associée à la lecture de lignes Yaml. * +* * +* Retour : Arborescence constituée par la lecture du contenu Yaml. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlTree *g_yaml_reader_get_tree(const GYamlReader *reader) +{ + GYamlTree *result; /* Arborescence à retourner */ + + result = reader->tree; + + g_object_ref(G_OBJECT(result)); + + return result; + +} diff --git a/plugins/yaml/reader.h b/plugins/yaml/reader.h new file mode 100644 index 0000000..3e5ce48 --- /dev/null +++ b/plugins/yaml/reader.h @@ -0,0 +1,69 @@ + +/* 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 . + */ + + +#ifndef PLUGINS_YAML_READER_H +#define PLUGINS_YAML_READER_H + + +#include +#include + + +#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/tree.c b/plugins/yaml/tree.c new file mode 100644 index 0000000..98ee30c --- /dev/null +++ b/plugins/yaml/tree.c @@ -0,0 +1,383 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * tree.c - 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 . + */ + + +#include "tree.h" + + +#include +#include + + + +/* Arborescence de lignes au format Yaml (instance) */ +struct _GYamlTree +{ + GObject parent; /* A laisser en premier */ + + size_t indent; /* Niveau d'indentation */ + + GYamlNode **nodes; /* Liste de noeuds à la racine */ + size_t count; /* Quantité de ces 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 un nouveau noeud dans une arborescence Yaml. */ +static GYamlNode *g_yaml_tree_build_node(GYamlLine **, 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->indent = 0; + + tree->nodes = NULL; + tree->count = 0; + +} + + +/****************************************************************************** +* * +* 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) +{ + size_t i; /* Boucle de parcours */ + + for (i = 0; i < tree->count; i++) + g_clear_object(&tree->nodes[i]); + + 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) +{ + if (tree->nodes != NULL) + free(tree->nodes); + + G_OBJECT_CLASS(g_yaml_tree_parent_class)->finalize(G_OBJECT(tree)); + +} + + +/****************************************************************************** +* * +* Paramètres : indent = indentation nominale pour les lignes à traiter. * +* 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(size_t indent, GYamlLine **lines, size_t count) +{ + GYamlTree *result; /* Structure à retourner */ + size_t cur; /* Boucle de parcours */ + GYamlNode *node; /* Nouveau noeud à intéger */ + + result = g_object_new(G_TYPE_YAML_TREE, NULL); + + result->indent = indent; + + for (cur = 0; cur < count; ) + { + node = g_yaml_tree_build_node(lines, count, &cur); + + if (node == NULL) + break; + + result->nodes = realloc(result->nodes, ++result->count * sizeof(GYamlNode *)); + + g_object_ref_sink(G_OBJECT(node)); + result->nodes[result->count - 1] = node; + + } + + if (cur < count) + { + 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. * +* cur = position courante dans les lignes. [OUT] * +* * +* Description : Construit un nouveau noeud dans une arborescence Yaml. * +* * +* Retour : Noeud mis en place ou NULL en cas d'erreur. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static GYamlNode *g_yaml_tree_build_node(GYamlLine **lines, size_t count, size_t *cur) +{ + GYamlNode *result; /* Structure à retourner */ + GYamlLine *line; /* Ligne de parcours courante */ + size_t cur_indent; /* Indentation courante */ + bool same_indent; /* Comparaison pour les enfants*/ + size_t next_indent; /* Indentation de la ligne */ + GYamlNode *child; /* Sous-noeud mis en place */ + + line = lines[(*cur)++]; + + result = g_yaml_node_new(line); + + /* Détermination de l'indentation associée */ + + cur_indent = g_yaml_line_count_indent(line); + + same_indent = g_yaml_line_is_list_item(line); + + /* Parcours du reste des lignes */ + + for (; *cur < count; ) + { + line = lines[*cur]; + + next_indent = g_yaml_line_count_indent(line); + + if ((same_indent && next_indent > cur_indent) + || (!same_indent && next_indent <= cur_indent)) + break; + + child = g_yaml_tree_build_node(lines, count, cur); + + if (child == NULL) + goto build_error; + + g_yaml_node_add_child(result, child); + + } + + return result; + + build_error: + + g_object_unref(G_OBJECT(result)); + + return NULL; + +} + + +/****************************************************************************** +* * +* Paramètres : tree = ligne au format Yaml à consulter. * +* * +* Description : Fournit la taille de l'indentation nomilae d'un arbre Yaml. * +* * +* Retour : Taille de l'indentation associée. * +* * +* Remarques : - * +* * +******************************************************************************/ + +size_t g_yaml_tree_get_indent(const GYamlTree *tree) +{ + size_t result; /* Quantité à retourner */ + + result = tree->indent; + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tree = ligne au format Yaml à consulter. * +* count = taille de la liste constituée. [OUT] * +* * +* Description : Fournit la liste des premiers noeuds de l'arborescence Yaml. * +* * +* Retour : Noeuds constituant les racines de l'arborescence. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count) +{ + GYamlNode **result; /* Liste à retourner */ + size_t i; /* Boucle de parcours */ + + *count = tree->count; + + result = malloc(*count * sizeof(GYamlNode *)); + + for (i = 0; i < *count; i++) + { + result[i] = tree->nodes[i]; + g_object_ref(G_OBJECT(result[i])); + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : tree = ligne au format Yaml à consulter. * +* path = chemin d'accès à parcourir. * +* * +* Description : Recherche le noeud correspondant à un chemin. * +* * +* Retour : Eventuel noeud trouvé ou NULL si aucun. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GYamlNode *g_yaml_tree_find_node_by_path(const GYamlTree *tree, const char *path) +{ + GYamlNode *result; /* Trouvaille à retourner */ + char *next; /* Prochaine partie du chemin */ + size_t cmplen; /* Etendue de la comparaison */ + size_t i; /* Boucle de parcours */ + GYamlLine *line; /* Ligne Yaml d'un enfant */ + const char *key; /* Clef d'un noeud */ + int ret; /* Bilan d'une comparaison */ + + result = NULL; + + if (path[0] == '/' && path[0] != '\0') + { + next = strchr(path + 1, '/'); + + cmplen = (next == NULL ? strlen(path + 1) : next - path - 1); + + for (i = 0; i < tree->count && result == NULL; i++) + { + line = g_yaml_node_get_yaml_line(tree->nodes[i]); + + key = g_yaml_line_get_key(line); + + ret = strncmp(path + 1, key, cmplen); + + if (ret == 0) + result = g_yaml_node_find_node_by_path(tree->nodes[i], next); + + } + + } + + return result; + +} diff --git a/plugins/yaml/tree.h b/plugins/yaml/tree.h new file mode 100644 index 0000000..469199d --- /dev/null +++ b/plugins/yaml/tree.h @@ -0,0 +1,69 @@ + +/* 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 . + */ + + +#ifndef PLUGINS_YAML_TREE_H +#define PLUGINS_YAML_TREE_H + + +#include +#include + + +#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(size_t, GYamlLine **, size_t); + +/* Fournit la taille de l'indentation nomilae d'un arbre Yaml. */ +size_t g_yaml_tree_get_indent(const GYamlTree *); + +/* Fournit la liste des premiers noeuds de l'arborescence Yaml. */ +GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *, size_t *); + +/* Recherche le noeud correspondant à un chemin. */ +GYamlNode *g_yaml_tree_find_node_by_path(const GYamlTree *, const char *); + + + +#endif /* PLUGINS_YAML_TREE_H */ diff --git a/tests/plugins/yamlrdr.py b/tests/plugins/yamlrdr.py new file mode 100644 index 0000000..7f65624 --- /dev/null +++ b/tests/plugins/yamlrdr.py @@ -0,0 +1,94 @@ +#!/usr/bin/python3-dbg +# -*- coding: utf-8 -*- + + +from chrysacase import ChrysalideTestCase +from pychrysalide.plugins.yaml import YamlReader +import tempfile + + +class TestYamlReader(ChrysalideTestCase): + """TestCase for the Yaml reader.""" + + + @classmethod + def setUpClass(cls): + + super(TestYamlReader, cls).setUpClass() + + cls._simple = tempfile.NamedTemporaryFile() + + cls.simple_data = b''' +meta: + id: java_class + endian: be + file-extension: class + xref: + justsolve: Java + pronom: x-fmt/415 + 'wiki"data': Q2193155 + license: CC0-1.0 + +''' + + cls._simple.write(cls.simple_data) + + cls._simple.flush() + + cls.log('Using temporary file "%s"' % cls._simple.name) + + + @classmethod + def tearDownClass(cls): + + super(TestYamlReader, cls).tearDownClass() + + cls.log('Delete file "%s"' % cls._simple.name) + + cls._simple.close() + + + def testSimpleYamlContent(self): + """Validate simple Yaml content reader.""" + + reader = YamlReader.new_from_path(self._simple.name) + self.assertIsNotNone(reader) + + + def _build_node_desc(node, left): + + line = node.yaml_line + + desc = left + line.key + ':' + (' ' + line.value if line.value else '') + '\n' + + for child in node.children: + desc += _build_node_desc(child, left + ' ') + + return desc + + + fulldesc = '' + + for rn in reader.tree.root_nodes: + fulldesc += _build_node_desc(rn, '') + + self.assertEqual('\n' + fulldesc + '\n', self.simple_data.decode('ascii')) + + + def testSimpleYamlContentFinder(self): + """Validate simple Yaml content search.""" + + reader = YamlReader.new_from_path(self._simple.name) + self.assertIsNotNone(reader) + + found = reader.tree.find_node_by_path('/meta/xref') + + self.assertEqual(found.yaml_line.key, 'xref') + + found = reader.tree.find_node_by_path('/meta/xref/') + + self.assertEqual(found.yaml_line.key, 'xref') + + found = reader.tree.find_node_by_path('/meta/xref/aa') + + self.assertIsNone(found) -- cgit v0.11.2-87-g4458