From e85f35454bf94b7414dd9d2f5e6609601951293c Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sat, 4 Feb 2023 17:36:10 +0100 Subject: Provide constructor to load Yaml contents without external files. --- plugins/yaml/line.c | 5 +- plugins/yaml/line.h | 2 +- plugins/yaml/python/line.c | 3 +- plugins/yaml/python/reader.c | 151 ++++++++++++++++---------------------- plugins/yaml/reader-int.h | 61 +++++++++++++++ plugins/yaml/reader.c | 171 ++++++++++++++++++++++--------------------- plugins/yaml/reader.h | 4 +- tests/plugins/yamlrdr.py | 69 ++++------------- 8 files changed, 233 insertions(+), 233 deletions(-) create mode 100644 plugins/yaml/reader-int.h diff --git a/plugins/yaml/line.c b/plugins/yaml/line.c index 26a1012..3466bb8 100644 --- a/plugins/yaml/line.c +++ b/plugins/yaml/line.c @@ -177,6 +177,7 @@ static void g_yaml_line_finalize(GYamlLine *line) /****************************************************************************** * * * Paramètres : raw = contenu brut d'une ligne au format Yaml. * +* rlen = taille de ce contenu brut. * * number = indice associé à la ligne. * * * * Description : Met en place un gestionnaire pour ligne au format Yaml. * @@ -187,7 +188,7 @@ static void g_yaml_line_finalize(GYamlLine *line) * * ******************************************************************************/ -GYamlLine *g_yaml_line_new(const char *raw, size_t number) +GYamlLine *g_yaml_line_new(const char *raw, size_t rlen, size_t number) { GYamlLine *result; /* Structure à retourner */ char *iter; /* Boucle de parcours */ @@ -196,7 +197,7 @@ GYamlLine *g_yaml_line_new(const char *raw, size_t number) result = g_object_new(G_TYPE_YAML_LINE, NULL); - result->raw = strdup(raw); + result->raw = strndup(raw, rlen); result->number = number; /* Indentation */ diff --git a/plugins/yaml/line.h b/plugins/yaml/line.h index 00f019e..5a3f942 100644 --- a/plugins/yaml/line.h +++ b/plugins/yaml/line.h @@ -49,7 +49,7 @@ typedef struct _GYamlLineClass GYamlLineClass; 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); +GYamlLine *g_yaml_line_new(const char *, size_t, size_t); /* Fournit la taille de l'indentation d'une ligne Yaml. */ size_t g_yaml_line_count_indent(const GYamlLine *); diff --git a/plugins/yaml/python/line.c b/plugins/yaml/python/line.c index 11898d2..f098273 100644 --- a/plugins/yaml/python/line.c +++ b/plugins/yaml/python/line.c @@ -26,6 +26,7 @@ #include +#include #include @@ -92,7 +93,7 @@ static PyObject *py_yaml_line_new(PyTypeObject *type, PyObject *args, PyObject * ret = PyArg_ParseTuple(args, "sn", &raw, &index); if (!ret) return NULL; - line = g_yaml_line_new(raw, index); + line = g_yaml_line_new(raw, strlen(raw), index); if (line == NULL) { diff --git a/plugins/yaml/python/reader.c b/plugins/yaml/python/reader.c index 74fd2b3..795b60c 100644 --- a/plugins/yaml/python/reader.c +++ b/plugins/yaml/python/reader.c @@ -28,25 +28,20 @@ #include +#include +#include #include +#include -#include "../reader.h" +#include "../reader-int.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." +CREATE_DYN_CONSTRUCTOR(yaml_reader, G_TYPE_YAML_READER); - - -/* 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 *); +/* Initialise une instance sur la base du dérivé de GObject. */ +static int py_yaml_reader_init(PyObject *, PyObject *, PyObject *); /* Fournit la liste des lignes lues depuis un contenu Yaml. */ static PyObject *py_yaml_reader_get_lines(PyObject *, void *); @@ -58,108 +53,90 @@ static PyObject *py_yaml_reader_get_tree(PyObject *, void *); /****************************************************************************** * * -* Paramètres : self = variable non utilisée ici. * +* Paramètres : self = objet à initialiser (théoriquement). * * args = arguments fournis à l'appel. * +* kwds = arguments de type key=val fournis. * * * -* Description : Crée un lecteur pour contenu au format Yaml. * +* Description : Initialise une instance sur la base du dérivé de GObject. * * * -* Retour : Instance mise en place ou None en cas d'échec. * +* Retour : 0. * * * * Remarques : - * * * ******************************************************************************/ -static PyObject *py_yaml_reader_new_from_content(PyObject *self, PyObject *args) +static int py_yaml_reader_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyObject *result; /* Instance à retourner */ - const char *content; /* Contenu brut au format Yaml */ - Py_ssize_t length; /* Taille de ce contenu */ + const char *text; /* Contenu de règles à traiter */ + const char *filename; /* Fichier de définitions */ int ret; /* Bilan de lecture des args. */ GYamlReader *reader; /* Création GLib à transmettre */ -#define YAML_READER_NEW_FROM_CONTENT_METHOD PYTHON_METHOD_DEF \ -( \ - new_from_content, "content", \ - METH_STATIC | METH_VARARGS, py_yaml_reader, \ - "Load a Yaml content." \ -) + static char *kwlist[] = { "text", "filename", NULL }; - /** - * La taille doit être de type 'int' et non 'Py_ssize_t', sinon les 32 bits - * de poids fort ne sont pas initialisés ! - */ +#define YAML_READER_DOC \ + "YamlReader is the class which aims to provide a reader interface" \ + " to Yaml content.\n" \ + "\n" \ + "Instances can be created using one of the following" \ + " constructors:\n" \ + "\n" \ + " YamlReader(text=str)" \ + "\n" \ + " YamlReader(filename=str)" \ + "\n" \ + "Where *text* is a string containg a markup content to parse;" \ + " the *filename* argument is an alternative string for a path" \ + " pointing to the same kind of content. This path can be a real" \ + " filename or a resource URI." \ + "\n" \ + "When parsing is successful, the Yaml content can be retrieved" \ + " line by line or thanks to a tree." - ret = PyArg_ParseTuple(args, "s#", &content, &length); - if (!ret) return NULL; + /* Récupération des paramètres */ - reader = g_yaml_reader_new_from_content(content, length); + text = NULL; + filename = NULL; - if (reader == NULL) - { - result = Py_None; - Py_INCREF(result); - } + ret = PyArg_ParseTupleAndKeywords(args, kwds, "|ss", kwlist, &text, &filename); + if (!ret) return -1; - else - { - g_object_ref_sink(G_OBJECT(reader)); - result = pygobject_new(G_OBJECT(reader)); - g_object_unref(reader); - } + /* Initialisation d'un objet GLib */ - return result; + ret = forward_pygobjet_init(self); + if (ret == -1) return -1; -} + /* Eléments de base */ + reader = G_YAML_READER(pygobject_get(self)); -/****************************************************************************** -* * -* Paramètres : self = variable non utilisée ici. * -* args = arguments fournis à l'appel. * -* * -* Description : Crée un lecteur pour contenu au format Yaml. * -* * -* Retour : Instance mise en place ou None en cas d'échec. * -* * -* Remarques : - * -* * -******************************************************************************/ - -static PyObject *py_yaml_reader_new_from_path(PyObject *self, PyObject *args) -{ - PyObject *result; /* Instance à retourner */ - const char *path; /* Chemin d'accès à un contenu */ - int ret; /* Bilan de lecture des args. */ - GYamlReader *reader; /* Création GLib à transmettre */ - -#define YAML_READER_NEW_FROM_PATH_METHOD PYTHON_METHOD_DEF \ -( \ - new_from_path, "path", \ - METH_STATIC | METH_VARARGS, py_yaml_reader, \ - "Load a Yaml content from a path.\n" \ - "\n" \ - "The path can be a filename or a resource URI." \ -) - - ret = PyArg_ParseTuple(args, "s", &path); - if (!ret) return NULL; + if (text != NULL) + { + if (!g_yaml_reader_create_from_text(reader, text)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Yaml reader.")); + return -1; + } - reader = g_yaml_reader_new_from_path(path); + } - if (reader == NULL) + else if (filename != NULL) { - result = Py_None; - Py_INCREF(result); + if (!g_yaml_reader_create_from_file(reader, filename)) + { + PyErr_SetString(PyExc_ValueError, _("Unable to create Yaml reader.")); + return -1; + } + } else { - g_object_ref_sink(G_OBJECT(reader)); - result = pygobject_new(G_OBJECT(reader)); - g_object_unref(reader); + PyErr_SetString(PyExc_ValueError, _("Unable to create empty Yaml reader.")); + return -1; } - return result; + return 0; } @@ -281,8 +258,6 @@ static PyObject *py_yaml_reader_get_tree(PyObject *self, void *closure) PyTypeObject *get_python_yaml_reader_type(void) { static PyMethodDef py_yaml_reader_methods[] = { - YAML_READER_NEW_FROM_CONTENT_METHOD, - YAML_READER_NEW_FROM_PATH_METHOD, { NULL } }; @@ -305,7 +280,9 @@ PyTypeObject *get_python_yaml_reader_type(void) .tp_methods = py_yaml_reader_methods, .tp_getset = py_yaml_reader_getseters, - .tp_new = no_python_constructor_allowed + + .tp_init = py_yaml_reader_init, + .tp_new = py_yaml_reader_new, }; diff --git a/plugins/yaml/reader-int.h b/plugins/yaml/reader-int.h new file mode 100644 index 0000000..aa985a1 --- /dev/null +++ b/plugins/yaml/reader-int.h @@ -0,0 +1,61 @@ + +/* Chrysalide - Outil d'analyse de fichiers binaires + * reader-int.h - prototypes internes pour le lecteur de contenu Yaml + * + * Copyright (C) 2023 Cyrille Bagard + * + * This file is part of Chrysalide. + * + * Chrysalide is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * Chrysalide is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Chrysalide. If not, see . + */ + + +#ifndef PLUGINS_YAML_READER_INT_H +#define PLUGINS_YAML_READER_INT_H + + +#include "reader.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 */ + +}; + + + +/* Met en place un lecteur pour contenu au format Yaml. */ +bool g_yaml_reader_create_from_text(GYamlReader *, const char *); + +/* Met en place un lecteur pour contenu au format Yaml. */ +bool g_yaml_reader_create_from_file(GYamlReader *, const char *); + + + +#endif /* PLUGINS_YAML_READER_INT_H */ diff --git a/plugins/yaml/reader.c b/plugins/yaml/reader.c index eebc02b..665e811 100644 --- a/plugins/yaml/reader.c +++ b/plugins/yaml/reader.c @@ -29,28 +29,12 @@ #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 */ +#include - GYamlTree *tree; /* Arborescence constituée */ -}; - -/* Lecteur de contenu Yaml (classe) */ -struct _GYamlReaderClass -{ - GObjectClass parent; /* A laisser en premier */ +#include "line.h" +#include "reader-int.h" -}; /* Initialise la classe des lecteurs de contenus Yaml. */ @@ -167,8 +151,7 @@ static void g_yaml_reader_finalize(GYamlReader *reader) /****************************************************************************** * * -* Paramètres : content = données brutes au format Yaml à charger. * -* length = quantité de ces données. * +* Paramètres : text = définitions textuelles d'un contenu brut. * * * * Description : Crée un lecteur pour contenu au format Yaml. * * * @@ -178,39 +161,64 @@ static void g_yaml_reader_finalize(GYamlReader *reader) * * ******************************************************************************/ -GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length) +GYamlReader *g_yaml_reader_new_from_text(const char *text) { GYamlReader *result; /* Structure à retourner */ - char *dumped; /* Contenu manipulable */ - char *saved; /* Sauvegarde de position */ - char *iter; /* Boucle de parcours */ - size_t number; /* Indice de ligne courante */ - GYamlLine *line; /* Nouvelle ligne Yaml */ result = g_object_new(G_TYPE_YAML_READER, NULL); - dumped = malloc(length * sizeof(char)); + if (!g_yaml_reader_create_from_text(result, text)) + g_clear_object(&result); - memcpy(dumped, content, length); + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : reader = lecteur de définition à initialiser pleinement. * +* text = définitions textuelles d'un contenu brut. * +* * +* Description : Met en place un lecteur pour contenu au format Yaml. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool g_yaml_reader_create_from_text(GYamlReader *reader, const char *text) +{ + bool result; /* Bilan à retourner */ + const char *saved; /* Sauvegarde de position */ + const char *iter; /* Boucle de parcours */ + size_t number; /* Indice de ligne courante */ + size_t rlen; /* Taille d'un contenu brut */ + GYamlLine *line; /* Nouvelle ligne Yaml */ - for (iter = dumped, saved = strchr(iter, '\n'), number = 0; + result = false; + + for (iter = text, saved = strchr(iter, '\n'), number = 0; *iter != '\0'; iter = ++saved, saved = strchr(iter, '\n'), number++) { - if (saved != NULL) - *saved = '\0'; + if (saved == NULL) + rlen = strlen(iter); + else + rlen = saved - iter; - if (*iter != '\0') + if (rlen > 0) { - line = g_yaml_line_new(iter, number); + line = g_yaml_line_new(iter, rlen, number); if (line == NULL) goto format_error; - result->lines = realloc(result->lines, ++result->count * sizeof(GYamlLine *)); + reader->lines = realloc(reader->lines, ++reader->count * sizeof(GYamlLine *)); g_object_ref_sink(G_OBJECT(line)); - result->lines[result->count - 1] = line; + reader->lines[reader->count - 1] = line; } @@ -219,24 +227,20 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length) } - free(dumped); + reader->tree = g_yaml_tree_new(reader->lines, reader->count); - result->tree = g_yaml_tree_new(result->lines, result->count); - - return result; + result = (reader->tree != NULL); format_error: - g_object_unref(G_OBJECT(result)); - - return NULL; + return result; } /****************************************************************************** * * -* Paramètres : path = chemin d'accès à un contenu à charger. * +* Paramètres : filename = chemin vers des définitions de règles. * * * * Description : Crée un lecteur pour contenu au format Yaml. * * * @@ -246,68 +250,65 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length) * * ******************************************************************************/ -GYamlReader *g_yaml_reader_new_from_path(const char *path) +GYamlReader *g_yaml_reader_new_from_file(const char *filename) { 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); + result = g_object_new(G_TYPE_YAML_READER, NULL); - stream = g_file_read(file, NULL, NULL); + if (!g_yaml_reader_create_from_file(result, filename)) + g_clear_object(&result); - if (stream == NULL) - goto no_content; + return result; - /* 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; +/****************************************************************************** +* * +* Paramètres : reader = lecteur de définition à initialiser pleinement. * +* filename = chemin vers des définitions de règles. * +* * +* Description : Met en place un lecteur pour contenu au format Yaml. * +* * +* Retour : Bilan de l'opération. * +* * +* Remarques : - * +* * +******************************************************************************/ - length = g_file_info_get_size(info); +bool g_yaml_reader_create_from_file(GYamlReader *reader, const char *filename) +{ + bool result; /* Bilan à retourner */ + GBinContent *content; /* Fichier à parcourir */ + phys_t size; /* Taille du contenu associé */ + vmpa2t start; /* Tête de lecture */ + const bin_t *data; /* Données à consulter */ + char *dumped; /* Contenu manipulable */ - /* Lecture des données */ + result = false; - content = malloc(length + 1 * sizeof(char)); + content = g_file_content_new(filename); + if (content == NULL) goto no_content; - if (!g_input_stream_read_all(G_INPUT_STREAM(stream), content, length, (gsize []) { 0 }, NULL, NULL)) - goto read_error; + size = g_binary_content_compute_size(content); - content[length] = '\0'; + g_binary_content_compute_start_pos(content, &start); + data = g_binary_content_get_raw_access(content, &start, size); - result = g_yaml_reader_new_from_content(content, length + 1); + dumped = malloc((size + 1) * sizeof(char)); - read_error: + memcpy(dumped, data, size); + dumped[size] = '\0'; - free(content); + result = g_yaml_reader_create_from_text(reader, dumped); - no_size_info: + free(dumped); - g_object_unref(G_OBJECT(stream)); + g_object_unref(G_OBJECT(content)); no_content: - g_object_unref(G_OBJECT(file)); - return result; } diff --git a/plugins/yaml/reader.h b/plugins/yaml/reader.h index 3e5ce48..51bd7e2 100644 --- a/plugins/yaml/reader.h +++ b/plugins/yaml/reader.h @@ -53,10 +53,10 @@ typedef struct _GYamlReaderClass GYamlReaderClass; 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); +GYamlReader *g_yaml_reader_new_from_text(const char *); /* Crée un lecteur pour contenu au format Yaml. */ -GYamlReader *g_yaml_reader_new_from_path(const char *); +GYamlReader *g_yaml_reader_new_from_file(const char *); /* Fournit la liste des lignes lues depuis un contenu Yaml. */ GYamlLine **g_yaml_reader_get_lines(const GYamlReader *, size_t *); diff --git a/tests/plugins/yamlrdr.py b/tests/plugins/yamlrdr.py index 47f02ba..b9a99a2 100644 --- a/tests/plugins/yamlrdr.py +++ b/tests/plugins/yamlrdr.py @@ -16,27 +16,21 @@ class TestYamlReader(ChrysalideTestCase): super(TestYamlReader, cls).setUpClass() - cls._simple_map = tempfile.NamedTemporaryFile() - - cls._simple_map_data = b''' + cls._simple_map_data = ''' a: av b: bv c: cv ''' - cls._simple_seq = tempfile.NamedTemporaryFile() - - cls._simple_seq_data = b''' + cls._simple_seq_data = ''' - a: av - b: bv - c: cv ''' - cls._nested = tempfile.NamedTemporaryFile() - - cls._nested_data = b''' + cls._nested_data = ''' root: a: v0 b: v1 @@ -52,9 +46,7 @@ root: ''' - cls._mixed = tempfile.NamedTemporaryFile() - - cls._mixed_data = b''' + cls._mixed_data = ''' root: - a: av aa: aav @@ -65,39 +57,6 @@ root: ''' - tmp = [ - [ cls._simple_map, cls._simple_map_data ], - [ cls._simple_seq, cls._simple_seq_data ], - [ cls._nested, cls._nested_data ], - [ cls._mixed, cls._mixed_data ], - ] - - for f, d in tmp: - - f.write(d) - f.flush() - - cls.log('Using temporary file "%s"' % f.name) - - - @classmethod - def tearDownClass(cls): - - super(TestYamlReader, cls).tearDownClass() - - tmp = [ - cls._simple_map, - cls._simple_seq, - cls._nested, - cls._mixed, - ] - - for f in tmp: - - cls.log('Delete file "%s"' % f.name) - - f.close() - def testSimpleYamlContent(self): """Validate Yaml content readers.""" @@ -133,43 +92,43 @@ root: return desc - reader = YamlReader.new_from_path(self._simple_map.name) + reader = YamlReader(text=self._simple_map_data) self.assertIsNotNone(reader) self.assertIsNotNone(reader.tree) fulldesc = _build_node_desc(reader.tree.root, '') - self.assertEqual('\n' + fulldesc + '\n', self._simple_map_data.decode('ascii')) + self.assertEqual('\n' + fulldesc + '\n', self._simple_map_data) - reader = YamlReader.new_from_path(self._simple_seq.name) + reader = YamlReader(text=self._simple_seq_data) self.assertIsNotNone(reader) self.assertIsNotNone(reader.tree) fulldesc = _build_node_desc(reader.tree.root, '') - self.assertEqual('\n' + fulldesc + '\n', self._simple_seq_data.decode('ascii')) + self.assertEqual('\n' + fulldesc + '\n', self._simple_seq_data) - reader = YamlReader.new_from_path(self._nested.name) + reader = YamlReader(text=self._nested_data) self.assertIsNotNone(reader) self.assertIsNotNone(reader.tree) fulldesc = _build_node_desc(reader.tree.root, '') - self.assertEqual('\n' + fulldesc + '\n', self._nested_data.decode('ascii')) + self.assertEqual('\n' + fulldesc + '\n', self._nested_data) - reader = YamlReader.new_from_path(self._mixed.name) + reader = YamlReader(text=self._mixed_data) self.assertIsNotNone(reader) self.assertIsNotNone(reader.tree) fulldesc = _build_node_desc(reader.tree.root, '') - self.assertEqual('\n' + fulldesc + '\n', self._mixed_data.decode('ascii')) + self.assertEqual('\n' + fulldesc + '\n', self._mixed_data) def testSimpleYamlContentFinder(self): """Validate Yaml nested content search.""" - reader = YamlReader.new_from_path(self._nested.name) + reader = YamlReader(text=self._nested_data) self.assertIsNotNone(reader) found = reader.tree.find_by_path('/root/sub') @@ -234,7 +193,7 @@ root: def testMixedYamlContentFinder(self): """Validate Yaml mixed content search.""" - reader = YamlReader.new_from_path(self._mixed.name) + reader = YamlReader(text=self._mixed_data) self.assertIsNotNone(reader) found = reader.tree.find_by_path('/root') -- cgit v0.11.2-87-g4458