summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/yaml/Makefile.am1
-rw-r--r--plugins/yaml/collection.c312
-rw-r--r--plugins/yaml/collection.h74
-rw-r--r--plugins/yaml/line.c23
-rw-r--r--plugins/yaml/line.h4
-rw-r--r--plugins/yaml/node.c192
-rw-r--r--plugins/yaml/node.h18
-rw-r--r--plugins/yaml/python/Makefile.am1
-rw-r--r--plugins/yaml/python/collection.c370
-rw-r--r--plugins/yaml/python/collection.h45
-rw-r--r--plugins/yaml/python/module.c2
-rw-r--r--plugins/yaml/python/node.c168
-rw-r--r--plugins/yaml/python/reader.c16
-rw-r--r--plugins/yaml/python/tree.c99
-rw-r--r--plugins/yaml/reader.c12
-rw-r--r--plugins/yaml/tree.c277
-rw-r--r--plugins/yaml/tree.h13
-rw-r--r--tests/plugins/yamlrdr.py174
18 files changed, 1407 insertions, 394 deletions
diff --git a/plugins/yaml/Makefile.am b/plugins/yaml/Makefile.am
index d7464b8..75e3cc2 100644
--- a/plugins/yaml/Makefile.am
+++ b/plugins/yaml/Makefile.am
@@ -27,6 +27,7 @@ endif
libyaml_la_SOURCES = \
+ collection.h collection.c \
core.h core.c \
line.h line.c \
node.h node.c \
diff --git a/plugins/yaml/collection.c b/plugins/yaml/collection.c
new file mode 100644
index 0000000..1615fa8
--- /dev/null
+++ b/plugins/yaml/collection.c
@@ -0,0 +1,312 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.h - collection de noeuds Yaml
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "collection.h"
+
+
+#include <malloc.h>
+
+
+
+/* Collection de noeuds au format Yaml (instance) */
+struct _GYamlCollection
+{
+ GObject parent; /* A laisser en premier */
+
+ bool is_seq; /* Nature de la collection */
+
+ GYamlNode **nodes; /* Sous-noeuds intégrés */
+ size_t count; /* Nombre de ces enfants */
+
+};
+
+/* Collection de noeuds au format Yaml (classe) */
+struct _GYamlCollectionClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Initialise la classe des collections de noeuds Yaml. */
+static void g_yaml_collection_class_init(GYamlCollectionClass *);
+
+/* Initialise une instance de collection de noeuds Yaml. */
+static void g_yaml_collection_init(GYamlCollection *);
+
+/* Supprime toutes les références externes. */
+static void g_yaml_collection_dispose(GYamlCollection *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_yaml_collection_finalize(GYamlCollection *);
+
+
+
+/* Indique le type défini pour une collection de noeuds Yaml. */
+G_DEFINE_TYPE(GYamlCollection, g_yaml_collection, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des collections de noeuds Yaml. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_yaml_collection_class_init(GYamlCollectionClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_collection_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_yaml_collection_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = instance à initialiser. *
+* *
+* Description : Initialise une instance de collection de noeuds Yaml. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_yaml_collection_init(GYamlCollection *collec)
+{
+ collec->is_seq = false;
+
+ collec->nodes = NULL;
+ collec->count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_yaml_collection_dispose(GYamlCollection *collec)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < collec->count; i++)
+ g_clear_object(&collec->nodes[i]);
+
+ G_OBJECT_CLASS(g_yaml_collection_parent_class)->dispose(G_OBJECT(collec));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_yaml_collection_finalize(GYamlCollection *collec)
+{
+ if (collec->nodes != NULL)
+ free(collec->nodes);
+
+ G_OBJECT_CLASS(g_yaml_collection_parent_class)->finalize(G_OBJECT(collec));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : seq = indique la nature de la future collection. *
+* *
+* Description : Construit une collection de noeuds Yaml. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GYamlCollection *g_yaml_collection_new(bool seq)
+{
+ GYamlCollection *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_YAML_COLLEC, NULL);
+
+ result->is_seq = seq;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = noeud d'arborescence Yaml à consulter. *
+* *
+* Description : Indique la nature d'une collection Yaml. *
+* *
+* Retour : Nature de la collection. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_yaml_collection_is_sequence(const GYamlCollection *collec)
+{
+ bool result; /* Statut à retourner */
+
+ result = collec->is_seq;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = collection de noeuds Yaml à compléter. *
+* node = noeud à rattacher. *
+* *
+* Description : Ajoute un noeud à une collection de noeuds Yaml. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_yaml_collection_add_node(GYamlCollection *collec, GYamlNode *node)
+{
+ collec->nodes = realloc(collec->nodes, ++collec->count * sizeof(GYamlNode *));
+
+ collec->nodes[collec->count - 1] = node;
+ g_object_ref_sink(G_OBJECT(node));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = noeud d'arborescence Yaml à consulter. *
+* count = taille de la liste constituée. [OUT] *
+* *
+* Description : Fournit la liste des noeuds intégrés dans une collection. *
+* *
+* Retour : Enfants d'un noeud issu d'une collection Yaml. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *collec, size_t *count)
+{
+ GYamlNode **result; /* Liste à retourner */
+ size_t i; /* Boucle de parcours */
+
+ *count = collec->count;
+
+ result = malloc(*count * sizeof(GYamlNode *));
+
+ for (i = 0; i < *count; i++)
+ {
+ result[i] = collec->nodes[i];
+ g_object_ref(G_OBJECT(result[i]));
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = noeud d'arborescence Yaml à consulter. *
+* path = chemin d'accès à parcourir. *
+* nodes = liste de noeuds avec correspondance établie. [OUT] *
+* count = quantité de ces noeuds. [OUT] *
+* *
+* Description : Recherche les noeuds correspondant à un chemin. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void _g_yaml_collection_find_by_path(const GYamlCollection *collec, const char *path, GYamlNode ***nodes, size_t *count)
+{
+ size_t i; /* Boucle de parcours */
+
+ for (i = 0; i < collec->count; i++)
+ _g_yaml_node_find_by_path(collec->nodes[i], path, nodes, count);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : collec = noeud d'arborescence Yaml à consulter. *
+* path = chemin d'accès à parcourir. *
+* nodes = liste de noeuds avec correspondance établie. [OUT] *
+* count = quantité de ces noeuds. [OUT] *
+* *
+* Description : Recherche les noeuds correspondant à un chemin. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_yaml_collection_find_by_path(const GYamlCollection *collec, const char *path, GYamlNode ***nodes, size_t *count)
+{
+ *nodes = NULL;
+ *count = 0;
+
+ _g_yaml_collection_find_by_path(collec, path, nodes, count);
+
+}
diff --git a/plugins/yaml/collection.h b/plugins/yaml/collection.h
new file mode 100644
index 0000000..71a2b46
--- /dev/null
+++ b/plugins/yaml/collection.h
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.h - prototypes pour une collection de noeuds Yaml
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_YAML_COLLECTION_H
+#define PLUGINS_YAML_COLLECTION_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "node.h"
+
+
+
+#define G_TYPE_YAML_COLLEC g_yaml_collection_get_type()
+#define G_YAML_COLLEC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_COLLEC, GYamlCollection))
+#define G_IS_YAML_COLLEC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_YAML_COLLEC))
+#define G_YAML_COLLEC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_YAML_COLLEC, GYamlCollectionClass))
+#define G_IS_YAML_COLLEC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_YAML_COLLEC))
+#define G_YAML_COLLEC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_YAML_COLLEC, GYamlCollectionClass))
+
+
+/* Collection de noeuds au format Yaml (instance) */
+typedef struct _GYamlCollection GYamlCollection;
+
+/* Collection de noeuds au format Yaml (classe) */
+typedef struct _GYamlCollectionClass GYamlCollectionClass;
+
+
+/* Indique le type défini pour une collection de noeuds Yaml. */
+GType g_yaml_collection_get_type(void);
+
+/* Construit une collection de noeuds Yaml. */
+GYamlCollection *g_yaml_collection_new(bool);
+
+/* Indique la nature d'une collection Yaml. */
+bool g_yaml_collection_is_sequence(const GYamlCollection *);
+
+/* Ajoute un noeud à une collection de noeuds Yaml. */
+void g_yaml_collection_add_node(GYamlCollection *, GYamlNode *);
+
+/* Fournit la liste des noeuds intégrés dans une collection. */
+GYamlNode **g_yaml_collection_get_nodes(const GYamlCollection *, size_t *);
+
+/* Recherche les noeuds correspondant à un chemin. */
+void g_yaml_collection_find_by_path(const GYamlCollection *, const char *, GYamlNode ***, size_t *);
+
+/* Recherche les noeuds correspondant à un chemin. */
+void _g_yaml_collection_find_by_path(const GYamlCollection *, const char *, GYamlNode ***, size_t *);
+
+
+
+#endif /* PLUGINS_YAML_COLLECTION_H */
diff --git a/plugins/yaml/line.c b/plugins/yaml/line.c
index cd993ee..26a1012 100644
--- a/plugins/yaml/line.c
+++ b/plugins/yaml/line.c
@@ -203,19 +203,20 @@ GYamlLine *g_yaml_line_new(const char *raw, size_t number)
for (iter = result->raw; *iter != '\0'; iter++)
{
- if (*iter != ' ' && *iter != '-')
+ if (*iter != ' ')
break;
result->indent++;
- if (*iter == '-')
- {
- if (result->is_list_item)
- goto format_error;
+ }
- result->is_list_item = true;
+ if (*iter == '-')
+ {
+ result->is_list_item = true;
- }
+ for (iter++; *iter != '\0'; iter++)
+ if (*iter != ' ')
+ break;
}
@@ -280,14 +281,6 @@ GYamlLine *g_yaml_line_new(const char *raw, size_t number)
return result;
- format_error:
-
- log_variadic_message(LMT_ERROR, "Yaml format error at line %zu", number);
-
- g_object_unref(G_OBJECT(result));
-
- return NULL;
-
}
diff --git a/plugins/yaml/line.h b/plugins/yaml/line.h
index b959272..00f019e 100644
--- a/plugins/yaml/line.h
+++ b/plugins/yaml/line.h
@@ -68,4 +68,8 @@ const char *g_yaml_line_get_value(const GYamlLine *);
+#define g_yaml_line_get_number(l) 0
+
+
+
#endif /* PLUGINS_YAML_LINE_H */
diff --git a/plugins/yaml/node.c b/plugins/yaml/node.c
index b0229c0..57eb3d2 100644
--- a/plugins/yaml/node.c
+++ b/plugins/yaml/node.c
@@ -28,6 +28,9 @@
#include <string.h>
+#include "collection.h"
+
+
/* Noeud d'une arborescence au format Yaml (instance) */
struct _GYamlNode
@@ -35,9 +38,7 @@ 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 */
+ GYamlCollection *collection; /* Collection de noeuds */
};
@@ -106,9 +107,7 @@ static void g_yaml_node_class_init(GYamlNodeClass *klass)
static void g_yaml_node_init(GYamlNode *node)
{
node->key = NULL;
-
- node->children = NULL;
- node->count = 0;
+ node->collection = NULL;
}
@@ -127,12 +126,9 @@ static void g_yaml_node_init(GYamlNode *node)
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_clear_object(&node->collection);
G_OBJECT_CLASS(g_yaml_node_parent_class)->dispose(G_OBJECT(node));
@@ -153,9 +149,6 @@ static void g_yaml_node_dispose(GYamlNode *node)
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));
}
@@ -179,8 +172,18 @@ GYamlNode *g_yaml_node_new(GYamlLine *key)
result = g_object_new(G_TYPE_YAML_NODE, NULL);
- result->key = key;
- g_object_ref(G_OBJECT(key));
+ /**
+ * Le paragraphe "3.2.2.1. Keys Order" des spécifications précise
+ * qu'une séquence n'est qu'un noeud sans correspondance clef/valeur.
+ *
+ * Cette situation doit donc être prise en compte.
+ */
+
+ if (key != NULL)
+ {
+ result->key = key;
+ g_object_ref(G_OBJECT(key));
+ }
return result;
@@ -189,7 +192,7 @@ GYamlNode *g_yaml_node_new(GYamlLine *key)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* Paramètres : node = noeud d'arborescence Yaml à consulter. *
* *
* Description : Fournit la ligne principale associée à un noeud. *
* *
@@ -205,7 +208,8 @@ GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node)
result = node->key;
- g_object_ref(G_OBJECT(result));
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
return result;
@@ -214,10 +218,10 @@ GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à compléter. *
-* child = noeud à rattacher. *
+* Paramètres : node = noeud d'arborescence Yaml à compléter. *
+* collec = collection de noeuds Yaml. *
* *
-* Description : Ajoute un noeud à un noeud d'une arborescence Yaml. *
+* Description : Attache une collection de noeuds Yaml à un noeud. *
* *
* Retour : - *
* *
@@ -225,43 +229,36 @@ GYamlLine *g_yaml_node_get_yaml_line(const GYamlNode *node)
* *
******************************************************************************/
-void g_yaml_node_add_child(GYamlNode *node, GYamlNode *child)
+void g_yaml_node_set_collection(GYamlNode *node, GYamlCollection *collec)
{
- node->children = realloc(node->children, ++node->count * sizeof(GYamlNode *));
+ g_clear_object(&node->collection);
- node->children[node->count - 1] = child;
- g_object_ref_sink(G_OBJECT(child));
+ g_object_ref_sink(G_OBJECT(collec));
+ node->collection = collec;
}
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* count = taille de la liste constituée. [OUT] *
+* Paramètres : node = noeud d'arborescence Yaml à consulter. *
* *
-* Description : Fournit la liste des noeuds intégrés dans un noeud Yaml. *
+* Description : Fournit une éventuelle collection rattachée à un noeud. *
* *
-* Retour : Enfants d'un noeud issu d'une arborescence Yaml. *
+* Retour : Collection de noeuds Yaml ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlNode **g_yaml_node_get_children(const GYamlNode *node, size_t *count)
+GYamlCollection *g_yaml_node_get_collection(const GYamlNode *node)
{
- GYamlNode **result; /* Liste à retourner */
- size_t i; /* Boucle de parcours */
+ GYamlCollection *result; /* Collection à renvoyer */
- *count = node->count;
+ result = node->collection;
- result = malloc(*count * sizeof(GYamlNode *));
-
- for (i = 0; i < *count; i++)
- {
- result[i] = node->children[i];
- g_object_ref(G_OBJECT(result[i]));
- }
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
return result;
@@ -270,66 +267,125 @@ GYamlNode **g_yaml_node_get_children(const GYamlNode *node, size_t *count)
/******************************************************************************
* *
-* Paramètres : node = noeud d'arborescence Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
+* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* path = chemin d'accès à parcourir. *
+* nodes = liste de noeuds avec correspondance établie. [OUT] *
+* count = quantité de ces noeuds. [OUT] *
* *
-* Description : Recherche le noeud correspondant à un chemin. *
+* Description : Recherche les noeuds correspondant à un chemin. *
* *
-* Retour : Eventuel noeud trouvé ou NULL si aucun. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlNode *g_yaml_node_find_node_by_path(GYamlNode *node, const char *path)
+void _g_yaml_node_find_by_path(GYamlNode *node, const char *path, GYamlNode ***nodes, size_t *count)
{
- GYamlNode *result; /* Trouvaille à retourner */
+ GYamlLine *line; /* Ligne Yaml liée au noeud */
+ const char *key; /* Clef associée au noeud */
+ bool matched; /* Correspondance établie ? */
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 */
+ GYamlCollection *collec; /* Collection de noeuds */
- result = NULL;
+ if (path[0] == '/')
+ path++;
- if (path[0] == '\0')
- result = node;
+ /* Correspondance au niveau du noeud ? */
- else if (path[0] == '/')
- {
- next = strchr(path + 1, '/');
+ line = g_yaml_node_get_yaml_line(node);
- cmplen = (next == NULL ? strlen(path + 1) : next - path - 1);
+ if (line != NULL)
+ {
+ key = g_yaml_line_get_key(line);
- if (cmplen == 0)
- result = node;
+ if (path[0] == '\0')
+ matched = true;
- for (i = 0; i < node->count && result == NULL; i++)
+ else
{
- line = g_yaml_node_get_yaml_line(node->children[i]);
+ next = strchr(path, '/');
+
+ cmplen = (next == NULL ? strlen(path) : next - path);
+
+ if (cmplen == 0)
+ goto cont;
- key = g_yaml_line_get_key(line);
+ ret = strncmp(path, key, cmplen);
- ret = strncmp(path + 1, key, cmplen);
+ if (ret != 0)
+ goto done;
- if (ret == 0)
+ else
{
- if (next != NULL)
- result = g_yaml_node_find_node_by_path(node->children[i], next);
+ if (next == NULL)
+ matched = true;
else
- result = node->children[i];
+ {
+ path += cmplen;
+ goto cont;
+ }
}
}
+ if (matched)
+ {
+ *nodes = realloc(*nodes, ++(*count) * sizeof(GYamlNode **));
+
+ g_object_ref(G_OBJECT(node));
+ (*nodes)[*count - 1] = node;
+
+ goto done;
+
+ }
+
}
- if (result != NULL)
- g_object_ref(G_OBJECT(result));
+ cont:
- return result;
+ collec = g_yaml_node_get_collection(node);
+
+ if (collec != NULL)
+ {
+ _g_yaml_collection_find_by_path(collec, path, nodes, count);
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ done:
+
+ if (line != NULL)
+ g_object_unref(G_OBJECT(line));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud d'arborescence Yaml à consulter. *
+* path = chemin d'accès à parcourir. *
+* nodes = liste de noeuds avec correspondance établie. [OUT] *
+* count = quantité de ces noeuds. [OUT] *
+* *
+* Description : Recherche les noeuds correspondant à un chemin. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+void g_yaml_node_find_by_path(GYamlNode *node, const char *path, GYamlNode ***nodes, size_t *count)
+{
+ *nodes = NULL;
+ *count = 0;
+
+ _g_yaml_node_find_by_path(node, path, nodes, count);
}
diff --git a/plugins/yaml/node.h b/plugins/yaml/node.h
index 582fa58..f1bbb23 100644
--- a/plugins/yaml/node.h
+++ b/plugins/yaml/node.h
@@ -32,6 +32,9 @@
#include "line.h"
+/* Depuis collection.h : collection de noeuds au format Yaml (instance) */
+typedef struct _GYamlCollection GYamlCollection;
+
#define G_TYPE_YAML_NODE g_yaml_node_get_type()
#define G_YAML_NODE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_YAML_NODE, GYamlNode))
@@ -57,14 +60,17 @@ 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 *);
+/* Attache une collection de noeuds Yaml à un noeud. */
+void g_yaml_node_set_collection(GYamlNode *, GYamlCollection *);
+
+/* Fournit une éventuelle collection rattachée à un noeud. */
+GYamlCollection *g_yaml_node_get_collection(const GYamlNode *);
-/* Fournit la liste des noeuds intégrés dans un noeud Yaml. */
-GYamlNode **g_yaml_node_get_children(const GYamlNode *, size_t *);
+/* Recherche les noeuds correspondant à un chemin. */
+void _g_yaml_node_find_by_path(GYamlNode *, const char *, GYamlNode ***, size_t *);
-/* Recherche le noeud correspondant à un chemin. */
-GYamlNode *g_yaml_node_find_node_by_path(GYamlNode *, const char *);
+/* Recherche les noeuds correspondant à un chemin. */
+void g_yaml_node_find_by_path(GYamlNode *, const char *, GYamlNode ***, size_t *);
diff --git a/plugins/yaml/python/Makefile.am b/plugins/yaml/python/Makefile.am
index 8a8d960..a750343 100644
--- a/plugins/yaml/python/Makefile.am
+++ b/plugins/yaml/python/Makefile.am
@@ -2,6 +2,7 @@
noinst_LTLIBRARIES = libyamlpython.la
libyamlpython_la_SOURCES = \
+ collection.h collection.c \
line.h line.c \
module.h module.c \
node.h node.c \
diff --git a/plugins/yaml/python/collection.c b/plugins/yaml/python/collection.c
new file mode 100644
index 0000000..7166784
--- /dev/null
+++ b/plugins/yaml/python/collection.c
@@ -0,0 +1,370 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.c - équivalent Python du fichier "plugins/yaml/collection.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 "collection.h"
+
+
+#include <pygobject.h>
+
+
+#include <plugins/pychrysalide/helpers.h>
+
+
+#include "../collection.h"
+
+
+
+/* Crée un nouvel objet Python de type 'YamlCollection'. */
+static PyObject *py_yaml_collection_new(PyTypeObject *, PyObject *, PyObject *);
+
+/* Recherche les noeuds correspondant à un chemin. */
+static PyObject *py_yaml_collection_find_by_path(PyObject *, PyObject *);
+
+/* Indique la nature d'une collection Yaml. */
+static PyObject *py_yaml_collection_is_sequence(PyObject *, void *);
+
+/* Fournit la liste des noeuds intégrés dans une collection. */
+static PyObject *py_yaml_collection_get_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 'YamlCollection'. *
+* *
+* Retour : Instance Python mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ PyObject *result; /* Instance à retourner */
+ int seq; /* Indicateur de type */
+ int ret; /* Bilan de lecture des args. */
+ GYamlCollection *collec; /* Création GLib à transmettre */
+
+#define YAML_COLLECTION_DOC \
+ "YamlCollection handle a collection of Yaml nodes.\n" \
+ "\n" \
+ "Instances can be created using the following constructor:\n" \
+ "\n" \
+ " YamlCollection(seq=False)\n" \
+ "\n" \
+ "Where seq defines if the collection will be a sequence or a mapping of nodes."
+
+ ret = PyArg_ParseTuple(args, "p", &seq);
+ if (!ret) return NULL;
+
+ collec = g_yaml_collection_new(seq);
+
+ g_object_ref_sink(G_OBJECT(collec));
+ result = pygobject_new(G_OBJECT(collec));
+ g_object_unref(collec);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = variable non utilisée ici. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Recherche les noeuds correspondant à un chemin. *
+* *
+* Retour : Liste de noeuds trouvés, éventuellement vide. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_find_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. */
+ GYamlCollection *collec; /* Version GLib du type */
+ GYamlNode **found; /* Créations GLib à transmettre*/
+ size_t count; /* Quantité de trouvailles */
+ size_t i; /* Boucle de parcours */
+
+#define YAML_COLLECTION_FIND_BY_PATH PYTHON_METHOD_DEF \
+( \
+ find_by_path, "path", \
+ METH_VARARGS, py_yaml_collection, \
+ "Find nodes from a Yaml node using a 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;
+
+ collec = G_YAML_COLLEC(pygobject_get(self));
+
+ g_yaml_collection_find_by_path(collec, path, &found, &count);
+
+ result = PyTuple_New(count);
+
+ for (i = 0; i < count; i++)
+ {
+#ifndef NDEBUG
+ ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+ assert(ret == 0);
+#else
+ PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+#endif
+
+ g_object_unref(G_OBJECT(found[i]));
+
+ }
+
+ if (found != NULL)
+ free(found);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Fournit la liste des noeuds intégrés dans une collection. *
+* *
+* Retour : Enfants d'un noeud issu d'une collection Yaml. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_get_nodes(PyObject *self, void *closure)
+{
+ PyObject *result; /* Résultat à retourner */
+ GYamlCollection *collec; /* 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_COLLECTION_NODES_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ nodes, py_yaml_collection, \
+ "List of nodes contained in the current collection." \
+)
+
+ collec = G_YAML_COLLEC(pygobject_get(self));
+
+ nodes = g_yaml_collection_get_nodes(collec, &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 : self = objet Python concerné par l'appel. *
+* closure = non utilisé ici. *
+* *
+* Description : Indique la nature d'une collection Yaml. *
+* *
+* Retour : Nature de la collection. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_yaml_collection_is_sequence(PyObject *self, void *closure)
+{
+ PyObject *result; /* Résultat à retourner */
+ GYamlCollection *collec; /* Version GLib du type */
+ bool status; /* Bilan de consultation */
+
+#define YAML_COLLECTION_IS_SEQUENCE_ATTRIB PYTHON_IS_DEF_FULL \
+( \
+ sequence, py_yaml_collection, \
+ "Nature of the collection: True is the collection is a sequence," \
+ " False if it is a mapping of \"key: value\" nodes." \
+)
+
+ collec = G_YAML_COLLEC(pygobject_get(self));
+
+ status = g_yaml_collection_is_sequence(collec);
+
+ result = status ? Py_True : Py_False;
+ Py_INCREF(result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : - *
+* *
+* Description : Fournit un accès à une définition de type à diffuser. *
+* *
+* Retour : Définition d'objet pour Python. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+PyTypeObject *get_python_yaml_collection_type(void)
+{
+ static PyMethodDef py_yaml_collection_methods[] = {
+ YAML_COLLECTION_FIND_BY_PATH,
+ { NULL }
+ };
+
+ static PyGetSetDef py_yaml_collection_getseters[] = {
+ YAML_COLLECTION_IS_SEQUENCE_ATTRIB,
+ YAML_COLLECTION_NODES_ATTRIB,
+ { NULL }
+ };
+
+ static PyTypeObject py_yaml_collection_type = {
+
+ PyVarObject_HEAD_INIT(NULL, 0)
+
+ .tp_name = "pychrysalide.plugins.yaml.YamlCollection",
+ .tp_basicsize = sizeof(PyGObject),
+
+ .tp_flags = Py_TPFLAGS_DEFAULT,
+
+ .tp_doc = YAML_COLLECTION_DOC,
+
+ .tp_methods = py_yaml_collection_methods,
+ .tp_getset = py_yaml_collection_getseters,
+ .tp_new = py_yaml_collection_new
+
+ };
+
+ return &py_yaml_collection_type;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : module = module dont la définition est à compléter. *
+* *
+* Description : Prend en charge l'objet 'pychrysalide.....YamlCollection. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool register_python_yaml_collection(PyObject *module)
+{
+ PyTypeObject *type; /* Type Python 'YamlCollection'*/
+ PyObject *dict; /* Dictionnaire du module */
+
+ type = get_python_yaml_collection_type();
+
+ dict = PyModule_GetDict(module);
+
+ if (!register_class_for_pygobject(dict, G_TYPE_YAML_COLLEC, 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 collection de noeuds de format Yaml. *
+* *
+* Retour : Bilan de l'opération, voire indications supplémentaires. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+int convert_to_yaml_collection(PyObject *arg, void *dst)
+{
+ int result; /* Bilan à retourner */
+
+ result = PyObject_IsInstance(arg, (PyObject *)get_python_yaml_collection_type());
+
+ switch (result)
+ {
+ case -1:
+ /* L'exception est déjà fixée par Python */
+ result = 0;
+ break;
+
+ case 0:
+ PyErr_SetString(PyExc_TypeError, "unable to convert the provided argument to Yaml collection");
+ break;
+
+ case 1:
+ *((GYamlCollection **)dst) = G_YAML_COLLEC(pygobject_get(arg));
+ break;
+
+ default:
+ assert(false);
+ break;
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/yaml/python/collection.h b/plugins/yaml/python/collection.h
new file mode 100644
index 0000000..ab2caba
--- /dev/null
+++ b/plugins/yaml/python/collection.h
@@ -0,0 +1,45 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * collection.h - prototypes pour l'équivalent Python du fichier "plugins/yaml/collection.h"
+ *
+ * Copyright (C) 2019 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR 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_COLLECTION_H
+#define _PLUGINS_YAML_PYTHON_COLLECTION_H
+
+
+#include <Python.h>
+#include <stdbool.h>
+
+
+
+/* Fournit un accès à une définition de type à diffuser. */
+PyTypeObject *get_python_yaml_collection_type(void);
+
+/* Prend en charge l'objet 'pychrysalide.plugins.yaml.YamlCollection'. */
+bool register_python_yaml_collection(PyObject *);
+
+/* Tente de convertir en collection de noeuds de format Yaml. */
+int convert_to_yaml_collection(PyObject *, void *);
+
+
+
+#endif /* _PLUGINS_YAML_PYTHON_COLLECTION_H */
diff --git a/plugins/yaml/python/module.c b/plugins/yaml/python/module.c
index 542a551..2a4401e 100644
--- a/plugins/yaml/python/module.c
+++ b/plugins/yaml/python/module.c
@@ -33,6 +33,7 @@
#include <plugins/pychrysalide/helpers.h>
+#include "collection.h"
#include "line.h"
#include "node.h"
#include "reader.h"
@@ -108,6 +109,7 @@ bool populate_yaml_module(void)
module = get_access_to_python_module("pychrysalide.plugins.yaml");
+ if (result) result = register_python_yaml_collection(module);
if (result) result = register_python_yaml_line(module);
if (result) result = register_python_yaml_node(module);
if (result) result = register_python_yaml_reader(module);
diff --git a/plugins/yaml/python/node.c b/plugins/yaml/python/node.c
index d1aabee..f2984d1 100644
--- a/plugins/yaml/python/node.c
+++ b/plugins/yaml/python/node.c
@@ -31,6 +31,7 @@
#include <plugins/pychrysalide/helpers.h>
+#include "collection.h"
#include "line.h"
#include "../node.h"
@@ -39,14 +40,17 @@
/* 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 *);
+/* Recherche les noeuds correspondant à un chemin. */
+static PyObject *py_yaml_node_find_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 *);
+/* Attache une collection de noeuds Yaml à un noeud. */
+static int py_yaml_node_set_collection(PyObject *, PyObject *, void *);
+
+/* Fournit une éventuelle collection rattachée à un noeud. */
+static PyObject *py_yaml_node_get_collection(PyObject *, void *);
@@ -99,27 +103,29 @@ static PyObject *py_yaml_node_new(PyTypeObject *type, PyObject *args, PyObject *
* Paramètres : self = variable non utilisée ici. *
* args = arguments fournis à l'appel. *
* *
-* Description : Recherche le noeud correspondant à un chemin. *
+* Description : Recherche les noeuds correspondant à un chemin. *
* *
-* Retour : Eventuel noeud trouvé ou NULL si aucun. *
+* Retour : Liste de noeuds trouvés, éventuellement vide. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_node_find_node_by_path(PyObject *self, PyObject *args)
+static PyObject *py_yaml_node_find_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 */
+ GYamlNode *node; /* Version GLib du noeud */
+ GYamlNode **found; /* Créations GLib à transmettre*/
+ size_t count; /* Quantité de trouvailles */
+ size_t i; /* Boucle de parcours */
#define YAML_NODE_FIND_BY_PATH PYTHON_METHOD_DEF \
( \
- find_node_by_path, "path", \
+ find_by_path, "path", \
METH_VARARGS, py_yaml_node, \
- "Find a child node in a Yaml node by its path.\n" \
+ "Find nodes from a Yaml node using a path.\n" \
"\n" \
"Paths are node keys separated by '/', such as '/my/path/to/node'." \
)
@@ -129,20 +135,26 @@ static PyObject *py_yaml_node_find_node_by_path(PyObject *self, PyObject *args)
node = G_YAML_NODE(pygobject_get(self));
- found = g_yaml_node_find_node_by_path(node, path);
+ g_yaml_node_find_by_path(node, path, &found, &count);
- if (found == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
+ result = PyTuple_New(count);
- else
+ for (i = 0; i < count; i++)
{
- result = pygobject_new(G_OBJECT(found));
- g_object_unref(found);
+#ifndef NDEBUG
+ ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+ assert(ret == 0);
+#else
+ PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+#endif
+
+ g_object_unref(G_OBJECT(found[i]));
+
}
+ if (found != NULL)
+ free(found);
+
return result;
}
@@ -164,7 +176,7 @@ static PyObject *py_yaml_node_find_node_by_path(PyObject *self, PyObject *args)
static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
{
PyObject *result; /* Résultat à retourner */
- GYamlNode *node; /* Version GLib du type */
+ GYamlNode *node; /* Version GLib du noeud */
GYamlLine *line; /* Line Yaml associée */
#define YAML_NODE_YAML_LINE_ATTRIB PYTHON_GET_DEF_FULL \
@@ -177,9 +189,65 @@ static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
line = g_yaml_node_get_yaml_line(node);
- result = pygobject_new(G_OBJECT(line));
+ if (line == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else
+ {
+ result = pygobject_new(G_OBJECT(line));
+ g_object_unref(G_OBJECT(line));
+ }
+
+ return result;
+
+}
+
+
+
+
+
+/******************************************************************************
+* *
+* Paramètres : self = contenu binaire à manipuler. *
+* value = collection de noeuds Yaml. *
+* closure = adresse non utilisée ici. *
+* *
+* Description : Attache une collection de noeuds Yaml à un noeud. *
+* *
+* Retour : Jeu d'attributs liés au contenu courant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int py_yaml_node_set_collection(PyObject *self, PyObject *value, void *closure)
+{
+ int result; /* Bilan à renvoyer */
+ GYamlNode *node; /* Version GLib du noeud */
+ GYamlCollection *collec; /* Version GLib de la valeur */
+
+ node = G_YAML_NODE(pygobject_get(self));
- g_object_unref(G_OBJECT(line));
+ if (value == Py_None)
+ {
+ g_yaml_node_set_collection(node, NULL);
+ result = 0;
+ }
+
+ else
+ {
+ if (!convert_to_yaml_collection(value, &collec))
+ result = -1;
+
+ else
+ {
+ g_yaml_node_set_collection(node, collec);
+ result = 0;
+ }
+
+ }
return result;
@@ -188,54 +256,44 @@ static PyObject *py_yaml_node_get_yaml_line(PyObject *self, void *closure)
/******************************************************************************
* *
-* Paramètres : self = objet Python concerné par l'appel. *
-* closure = non utilisé ici. *
+* Paramètres : self = contenu binaire à manipuler. *
+* closure = adresse non utilisée ici. *
* *
-* Description : Fournit la liste des noeuds intégrés dans un noeud Yaml. *
+* Description : Fournit une éventuelle collection rattachée à un noeud. *
* *
-* Retour : Enfants d'un noeud issu d'une arborescence Yaml. *
+* Retour : Collection de noeuds Yaml ou None. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_node_get_children(PyObject *self, void *closure)
+static PyObject *py_yaml_node_get_collection(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
+ PyObject *result; /* Instance à retourner */
+ GYamlNode *node; /* Version GLib du noeud */
+ GYamlCollection *collec; /* Collection à transmettre */
-#define YAML_NODE_CHILDREN_ATTRIB PYTHON_GET_DEF_FULL \
-( \
- children, py_yaml_node, \
- "List of nodes which are children of the current node." \
+#define YAML_NODE_COLLECTION_ATTRIB PYTHON_GETSET_DEF_FULL \
+( \
+ collection, py_yaml_node, \
+ "Provide or define the collection of nodes attached to another Yaml node." \
)
node = G_YAML_NODE(pygobject_get(self));
- nodes = g_yaml_node_get_children(node, &count);
+ collec = g_yaml_node_get_collection(node);
- result = PyTuple_New(count);
-
- for (i = 0; i < count; i++)
+ if (collec == NULL)
{
-#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]));
-
+ result = Py_None;
+ Py_INCREF(result);
}
- free(nodes);
+ else
+ {
+ result = pygobject_new(G_OBJECT(collec));
+ g_object_unref(collec);
+ }
return result;
@@ -263,7 +321,7 @@ PyTypeObject *get_python_yaml_node_type(void)
static PyGetSetDef py_yaml_node_getseters[] = {
YAML_NODE_YAML_LINE_ATTRIB,
- YAML_NODE_CHILDREN_ATTRIB,
+ YAML_NODE_COLLECTION_ATTRIB,
{ NULL }
};
diff --git a/plugins/yaml/python/reader.c b/plugins/yaml/python/reader.c
index 43db6bb..809ece2 100644
--- a/plugins/yaml/python/reader.c
+++ b/plugins/yaml/python/reader.c
@@ -208,7 +208,8 @@ static PyObject *py_yaml_reader_get_lines(PyObject *self, void *closure)
}
- free(lines);
+ if (lines != NULL)
+ free(lines);
return result;
@@ -244,9 +245,16 @@ static PyObject *py_yaml_reader_get_tree(PyObject *self, void *closure)
tree = g_yaml_reader_get_tree(reader);
- result = pygobject_new(G_OBJECT(tree));
-
- g_object_unref(G_OBJECT(tree));
+ if (tree == NULL)
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+ else
+ {
+ result = pygobject_new(G_OBJECT(tree));
+ g_object_unref(G_OBJECT(tree));
+ }
return result;
diff --git a/plugins/yaml/python/tree.c b/plugins/yaml/python/tree.c
index 9e1a2a3..eeab3de 100644
--- a/plugins/yaml/python/tree.c
+++ b/plugins/yaml/python/tree.c
@@ -40,11 +40,11 @@
/* 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 *);
+/* Recherche les noeuds correspondant à un chemin. */
+static PyObject *py_yaml_tree_find_by_path(PyObject *, PyObject *);
-/* Fournit la liste des premiers noeuds de l'arborescence Yaml. */
-static PyObject *py_yaml_tree_get_root_nodes(PyObject *, void *);
+/* Fournit le noeud constituant la racine d'arborescence Yaml. */
+static PyObject *py_yaml_tree_get_root(PyObject *, void *);
@@ -65,7 +65,6 @@ static PyObject *py_yaml_tree_get_root_nodes(PyObject *, void *);
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 */
@@ -80,12 +79,11 @@ static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *
"\n" \
"Instances can be created using the following constructor:\n" \
"\n" \
- " YamlTree(indent, lines)" \
+ " YamlTree(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."
+ "Where lines are a tuple of Yaml lines used to built the tree."
- ret = PyArg_ParseTuple(args, "nO!", &indent, &PyTuple_Type, &tuple);
+ ret = PyArg_ParseTuple(args, "O!", &PyTuple_Type, &tuple);
if (!ret) return NULL;
count = PyTuple_Size(tuple);
@@ -106,7 +104,7 @@ static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *
}
- tree = g_yaml_tree_new(indent, lines, count);
+ tree = g_yaml_tree_new(lines, count);
arg_error:
@@ -141,27 +139,29 @@ static PyObject *py_yaml_tree_new(PyTypeObject *type, PyObject *args, PyObject *
* Paramètres : self = variable non utilisée ici. *
* args = arguments fournis à l'appel. *
* *
-* Description : Recherche le noeud correspondant à un chemin. *
+* Description : Recherche les noeuds correspondant à un chemin. *
* *
-* Retour : Eventuel noeud trouvé ou NULL si aucun. *
+* Retour : Liste de noeuds trouvés, éventuellement vide. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_tree_find_node_by_path(PyObject *self, PyObject *args)
+static PyObject *py_yaml_tree_find_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 */
+ GYamlNode **found; /* Créations GLib à transmettre*/
+ size_t count; /* Quantité de trouvailles */
+ size_t i; /* Boucle de parcours */
#define YAML_TREE_FIND_BY_PATH PYTHON_METHOD_DEF \
( \
- find_node_by_path, "path", \
+ find_by_path, "path", \
METH_VARARGS, py_yaml_tree, \
- "Find a node in a Yaml tree by its path.\n" \
+ "Find nodes in a Yaml tree using a path.\n" \
"\n" \
"Paths are node keys separated by '/', such as '/my/path/to/node'." \
)
@@ -171,20 +171,26 @@ static PyObject *py_yaml_tree_find_node_by_path(PyObject *self, PyObject *args)
tree = G_YAML_TREE(pygobject_get(self));
- found = g_yaml_tree_find_node_by_path(tree, path);
+ g_yaml_tree_find_by_path(tree, path, &found, &count);
- if (found == NULL)
- {
- result = Py_None;
- Py_INCREF(result);
- }
+ result = PyTuple_New(count);
- else
+ for (i = 0; i < count; i++)
{
- result = pygobject_new(G_OBJECT(found));
- g_object_unref(found);
+#ifndef NDEBUG
+ ret = PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+ assert(ret == 0);
+#else
+ PyTuple_SetItem(result, i, pygobject_new(G_OBJECT(found[i])));
+#endif
+
+ g_object_unref(G_OBJECT(found[i]));
+
}
+ if (found != NULL)
+ free(found);
+
return result;
}
@@ -195,51 +201,32 @@ static PyObject *py_yaml_tree_find_node_by_path(PyObject *self, PyObject *args)
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
-* Description : Fournit la liste des premiers noeuds de l'arborescence Yaml. *
+* Description : Fournit le noeud constituant la racine d'arborescence Yaml. *
* *
-* Retour : Noeuds constituant les racines de l'arborescence. *
+* Retour : Noeud constituant la racine de l'arborescence. *
* *
* Remarques : - *
* *
******************************************************************************/
-static PyObject *py_yaml_tree_get_root_nodes(PyObject *self, void *closure)
+static PyObject *py_yaml_tree_get_root(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
+ GYamlNode *root; /* Noeud racine d'arborescence */
-#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." \
+#define YAML_TREE_ROOT_ATTRIB PYTHON_GET_DEF_FULL \
+( \
+ root, py_yaml_tree, \
+ "Yaml node which is the root of the whole tree nodes." \
)
tree = G_YAML_TREE(pygobject_get(self));
- 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]));
-
- }
+ root = g_yaml_tree_get_root(tree);
- free(nodes);
+ result = pygobject_new(G_OBJECT(root));
+ g_object_unref(G_OBJECT(root));
return result;
@@ -266,7 +253,7 @@ PyTypeObject *get_python_yaml_tree_type(void)
};
static PyGetSetDef py_yaml_tree_getseters[] = {
- YAML_TREE_ROOT_NODES_ATTRIB,
+ YAML_TREE_ROOT_ATTRIB,
{ NULL }
};
diff --git a/plugins/yaml/reader.c b/plugins/yaml/reader.c
index 02e1aa9..c8852bb 100644
--- a/plugins/yaml/reader.c
+++ b/plugins/yaml/reader.c
@@ -182,7 +182,6 @@ 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 */
@@ -194,8 +193,6 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
memcpy(dumped, content, length);
- level = 0;
-
for (iter = dumped, saved = strchr(iter, '\n'), number = 0;
*iter != '\0';
iter = ++saved, saved = strchr(iter, '\n'), number++)
@@ -210,9 +207,6 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
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));
@@ -222,8 +216,7 @@ GYamlReader *g_yaml_reader_new_from_content(const char *content, size_t length)
free(dumped);
- result->tree = g_yaml_tree_new(level, result->lines, result->count);
- g_object_ref_sink(G_OBJECT(result->tree));
+ result->tree = g_yaml_tree_new(result->lines, result->count);
return result;
@@ -366,7 +359,8 @@ GYamlTree *g_yaml_reader_get_tree(const GYamlReader *reader)
result = reader->tree;
- g_object_ref(G_OBJECT(result));
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
return result;
diff --git a/plugins/yaml/tree.c b/plugins/yaml/tree.c
index 98ee30c..0494aeb 100644
--- a/plugins/yaml/tree.c
+++ b/plugins/yaml/tree.c
@@ -24,20 +24,25 @@
#include "tree.h"
+#include <assert.h>
#include <malloc.h>
#include <string.h>
+#include <i18n.h>
+#include <core/logs.h>
+
+
+#include "collection.h"
+
+
/* 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 */
+ GYamlNode *root; /* Racine des noeuds */
};
@@ -61,8 +66,8 @@ 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 *);
+/* Construit une collection de noeuds avec une arborescence. */
+static bool g_yaml_tree_build_node(GYamlCollection *, GYamlLine **, size_t, size_t, size_t *);
@@ -108,10 +113,7 @@ static void g_yaml_tree_class_init(GYamlTreeClass *klass)
static void g_yaml_tree_init(GYamlTree *tree)
{
- tree->indent = 0;
-
- tree->nodes = NULL;
- tree->count = 0;
+ tree->root = NULL;
}
@@ -130,10 +132,7 @@ static void g_yaml_tree_init(GYamlTree *tree)
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_clear_object(&tree->root);
G_OBJECT_CLASS(g_yaml_tree_parent_class)->dispose(G_OBJECT(tree));
@@ -154,9 +153,6 @@ static void g_yaml_tree_dispose(GYamlTree *tree)
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));
}
@@ -164,8 +160,7 @@ static void g_yaml_tree_finalize(GYamlTree *tree)
/******************************************************************************
* *
-* Paramètres : indent = indentation nominale pour les lignes à traiter. *
-* lines = ensemble de lignes à constituer en arborescence. *
+* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
* count = taille de cet ensemble de lignes. *
* *
* Description : Construit une arborescence à partir de lignes Yaml. *
@@ -176,34 +171,37 @@ static void g_yaml_tree_finalize(GYamlTree *tree)
* *
******************************************************************************/
-GYamlTree *g_yaml_tree_new(size_t indent, GYamlLine **lines, size_t count)
+GYamlTree *g_yaml_tree_new(GYamlLine **lines, size_t count)
{
GYamlTree *result; /* Structure à retourner */
- size_t cur; /* Boucle de parcours */
- GYamlNode *node; /* Nouveau noeud à intéger */
+ GYamlCollection *collec; /* Collection de noeuds */
+ size_t indent; /* Indentation initiale */
+ size_t processed; /* Quantité de noeuds traités */
+ bool status; /* Bilan de construction */
result = g_object_new(G_TYPE_YAML_TREE, NULL);
- result->indent = indent;
-
- for (cur = 0; cur < count; )
+ if (count > 0)
{
- node = g_yaml_tree_build_node(lines, count, &cur);
+ result->root = g_yaml_node_new(NULL);
- if (node == NULL)
- break;
+ collec = g_yaml_collection_new(g_yaml_line_is_list_item(lines[0]));
+ g_yaml_node_set_collection(result->root, collec);
- result->nodes = realloc(result->nodes, ++result->count * sizeof(GYamlNode *));
+ indent = g_yaml_line_count_indent(lines[0]);
+ processed = 0;
- g_object_ref_sink(G_OBJECT(node));
- result->nodes[result->count - 1] = node;
+ status = g_yaml_tree_build_node(collec, lines, count, indent, &processed);
- }
+ if (status)
+ assert(processed == count);
+
+ else
+ {
+ g_object_unref(G_OBJECT(result));
+ result = NULL;
+ }
- if (cur < count)
- {
- g_object_unref(G_OBJECT(result));
- result = NULL;
}
return result;
@@ -213,86 +211,129 @@ GYamlTree *g_yaml_tree_new(size_t indent, GYamlLine **lines, size_t count)
/******************************************************************************
* *
-* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
-* count = taille de cet ensemble de lignes. *
-* cur = position courante dans les lignes. [OUT] *
+* Paramètres : lines = ensemble de lignes à constituer en arborescence. *
+* count = taille de cet ensemble de lignes. *
+* expected = niveau d'identation attendu. *
+* cur = position courante dans les lignes. [OUT] *
* *
-* Description : Construit un nouveau noeud dans une arborescence Yaml. *
+* Description : Construit une collection de noeuds avec une arborescence. *
* *
-* Retour : Noeud mis en place ou NULL en cas d'erreur. *
+* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
-static GYamlNode *g_yaml_tree_build_node(GYamlLine **lines, size_t count, size_t *cur)
+static bool g_yaml_tree_build_node(GYamlCollection *collec, GYamlLine **lines, size_t count, size_t expected, size_t *cur)
{
- GYamlNode *result; /* Structure à retourner */
+ bool result; /* Bilan à retourner */
+ bool first; /* Marque d'un premier élément */
+ GYamlNode *last; /* Mémorisation du dernier */
GYamlLine *line; /* Ligne de parcours courante */
- size_t 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 */
+ size_t indent; /* Indentation de ligne */
+ bool is_item; /* Elément d'une liste ? */
+ GYamlCollection *sub; /* Nouvelle sous-collection */
+ GYamlNode *glue; /* Noeud vide intermédiaire */
- line = lines[(*cur)++];
+ result = true;
- result = g_yaml_node_new(line);
+ first = true;
+ last = NULL;
- /* Détermination de l'indentation associée */
+ for (; *cur < count; )
+ {
+ line = lines[*cur];
- cur_indent = g_yaml_line_count_indent(line);
+ indent = g_yaml_line_count_indent(line);
+ is_item = g_yaml_line_is_list_item(line);
+
+ /**
+ * Si la première ligne traitée commence par un élément de liste,
+ * alors un appel parent a constitué une collection qui n'est pas une séquence.
+ *
+ * L'objectif est de créer une simple association de 'clefs: valeurs'.
+ *
+ * Si la collection n'est pas adapté, alors le parcours n'est pas encore
+ * arrivé à ce stade de construction.
+ */
+ if (first && is_item && !g_yaml_collection_is_sequence(collec))
+ {
+ indent += 2; /* 2 == strlen("- ") */
+ is_item = false;
+ }
- same_indent = g_yaml_line_is_list_item(line);
+ first = false;
- /* Parcours du reste des lignes */
+ /* Fin de l'ensemble courant */
+ if (indent < expected)
+ goto done;
- for (; *cur < count; )
- {
- line = lines[*cur];
+ /* Début d'un sous-ensemble */
+ else if (indent > expected)
+ {
+ assert(last != NULL);
- next_indent = g_yaml_line_count_indent(line);
+ sub = g_yaml_collection_new(is_item);
+ g_yaml_node_set_collection(last, sub);
- if ((same_indent && next_indent > cur_indent)
- || (!same_indent && next_indent <= cur_indent))
- break;
+ result = g_yaml_tree_build_node(sub, lines, count, indent, cur);
+ if (!result) goto done;
- child = g_yaml_tree_build_node(lines, count, cur);
+ }
- if (child == NULL)
- goto build_error;
+ /* Elément de même niveau */
+ else
+ {
+ if (is_item)
+ {
+ /* Vérification de cohérence */
+ if (!g_yaml_collection_is_sequence(collec))
+ {
+ log_variadic_message(LMT_BAD_BINARY, _("A mapping item was expected at line %zu"),
+ g_yaml_line_get_number(line));
- g_yaml_node_add_child(result, child);
+ result = false;
+ goto done;
- }
+ }
- return result;
+ glue = g_yaml_node_new(NULL);
+ g_yaml_collection_add_node(collec, glue);
- build_error:
+ sub = g_yaml_collection_new(false);
+ g_yaml_node_set_collection(glue, sub);
- g_object_unref(G_OBJECT(result));
+ result = g_yaml_tree_build_node(sub, lines, count, expected + 2 /* 2 == strlen("- ") */, cur);
+ if (!result) goto done;
- return NULL;
+ }
-}
+ else
+ {
+ /* Vérification de cohérence */
+ if (g_yaml_collection_is_sequence(collec))
+ {
+ log_variadic_message(LMT_BAD_BINARY, _("A list item was expected at line %zu"),
+ g_yaml_line_get_number(line));
-/******************************************************************************
-* *
-* 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 : - *
-* *
-******************************************************************************/
+ result = false;
+ goto done;
-size_t g_yaml_tree_get_indent(const GYamlTree *tree)
-{
- size_t result; /* Quantité à retourner */
+ }
+
+ last = g_yaml_node_new(line);
+ g_yaml_collection_add_node(collec, last);
+
+ (*cur)++;
+
+ }
+
+ }
+
+ }
- result = tree->indent;
+ done:
return result;
@@ -302,30 +343,21 @@ size_t g_yaml_tree_get_indent(const GYamlTree *tree)
/******************************************************************************
* *
* 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. *
+* Description : Fournit le noeud constituant la racine d'arborescence Yaml. *
* *
-* Retour : Noeuds constituant les racines de l'arborescence. *
+* Retour : Noeud constituant la racine de l'arborescence. *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count)
+GYamlNode *g_yaml_tree_get_root(const GYamlTree *tree)
{
- GYamlNode **result; /* Liste à retourner */
- size_t i; /* Boucle de parcours */
-
- *count = tree->count;
+ GYamlNode *result; /* Liste à retourner */
- result = malloc(*count * sizeof(GYamlNode *));
-
- for (i = 0; i < *count; i++)
- {
- result[i] = tree->nodes[i];
- g_object_ref(G_OBJECT(result[i]));
- }
+ result = tree->root;
+ g_object_ref(G_OBJECT(result));
return result;
@@ -334,50 +366,21 @@ GYamlNode **g_yaml_tree_get_root_nodes(const GYamlTree *tree, size_t *count)
/******************************************************************************
* *
-* Paramètres : tree = ligne au format Yaml à consulter. *
-* path = chemin d'accès à parcourir. *
+* Paramètres : tree = ligne au format Yaml à consulter. *
+* path = chemin d'accès à parcourir. *
+* nodes = liste de noeuds avec correspondance établie. [OUT] *
+* count = quantité de ces noeuds. [OUT] *
* *
-* Description : Recherche le noeud correspondant à un chemin. *
+* Description : Recherche les noeuds correspondant à un chemin. *
* *
-* Retour : Eventuel noeud trouvé ou NULL si aucun. *
+* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
-GYamlNode *g_yaml_tree_find_node_by_path(const GYamlTree *tree, const char *path)
+void g_yaml_tree_find_by_path(const GYamlTree *tree, const char *path, GYamlNode ***nodes, size_t *count)
{
- 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;
+ g_yaml_node_find_by_path(tree->root, path, nodes, count);
}
diff --git a/plugins/yaml/tree.h b/plugins/yaml/tree.h
index 469199d..d152b7e 100644
--- a/plugins/yaml/tree.h
+++ b/plugins/yaml/tree.h
@@ -53,16 +53,13 @@ typedef struct _GYamlTreeClass GYamlTreeClass;
GType g_yaml_tree_get_type(void);
/* Construit une arborescence à partir de lignes Yaml. */
-GYamlTree *g_yaml_tree_new(size_t, GYamlLine **, size_t);
+GYamlTree *g_yaml_tree_new(GYamlLine **, size_t);
-/* Fournit la taille de l'indentation nomilae d'un arbre Yaml. */
-size_t g_yaml_tree_get_indent(const GYamlTree *);
+/* Fournit le noeud constituant la racine d'arborescence Yaml. */
+GYamlNode *g_yaml_tree_get_root(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 *);
+/* Recherche les noeuds correspondant à un chemin. */
+void g_yaml_tree_find_by_path(const GYamlTree *, const char *, GYamlNode ***, size_t *);
diff --git a/tests/plugins/yamlrdr.py b/tests/plugins/yamlrdr.py
index 7f65624..103d6e8 100644
--- a/tests/plugins/yamlrdr.py
+++ b/tests/plugins/yamlrdr.py
@@ -16,26 +16,54 @@ class TestYamlReader(ChrysalideTestCase):
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_map = tempfile.NamedTemporaryFile()
+
+ cls._simple_map_data = b'''
+a: av
+b: bv
+c: cv
+
+'''
+
+ cls._simple_seq = tempfile.NamedTemporaryFile()
+
+ cls._simple_seq_data = b'''
+- a: av
+- b: bv
+- c: cv
'''
- cls._simple.write(cls.simple_data)
+ cls._nested = tempfile.NamedTemporaryFile()
+
+ cls._nested_data = b'''
+root:
+ a: v0
+ b: v1
+ c: v2
+ sub:
+ aa: v00
+ bb: v01
+ cc: v02
+ - i: w
+ - j: x
+ - k: c
+ d: v3
- cls._simple.flush()
+'''
- cls.log('Using temporary file "%s"' % cls._simple.name)
+ tmp = [
+ [ cls._simple_map, cls._simple_map_data ],
+ [ cls._simple_seq, cls._simple_seq_data ],
+ [ cls._nested, cls._nested_data ]
+ ]
+
+ for f, d in tmp:
+
+ f.write(d)
+ f.flush()
+
+ cls.log('Using temporary file "%s"' % f.name)
@classmethod
@@ -43,52 +71,126 @@ meta:
super(TestYamlReader, cls).tearDownClass()
- cls.log('Delete file "%s"' % cls._simple.name)
+ tmp = [
+ cls._simple_map,
+ cls._simple_seq,
+ cls._nested,
+ ]
- cls._simple.close()
+ for f in tmp:
+ cls.log('Delete file "%s"' % f.name)
- def testSimpleYamlContent(self):
- """Validate simple Yaml content reader."""
+ f.close()
- reader = YamlReader.new_from_path(self._simple.name)
- self.assertIsNotNone(reader)
+ def testSimpleYamlContent(self):
+ """Validate Yaml content readers."""
def _build_node_desc(node, left):
line = node.yaml_line
- desc = left + line.key + ':' + (' ' + line.value if line.value else '') + '\n'
+ if line:
+ prefix = '- ' if line.is_list_item else ''
+ desc = left + prefix + line.key + ':' + (' ' + line.value if line.value else '') + '\n'
+ indent = ' '
+ else:
+ desc = ''
+ indent = ''
- for child in node.children:
- desc += _build_node_desc(child, left + ' ')
+ if node.collection:
+ for child in node.collection.nodes:
+ desc += _build_node_desc(child, left + indent)
return desc
- fulldesc = ''
+ reader = YamlReader.new_from_path(self._simple_map.name)
+ 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'))
+
+ reader = YamlReader.new_from_path(self._simple_seq.name)
+ 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'))
+
+ reader = YamlReader.new_from_path(self._nested.name)
+ self.assertIsNotNone(reader)
+ self.assertIsNotNone(reader.tree)
- for rn in reader.tree.root_nodes:
- fulldesc += _build_node_desc(rn, '')
+ fulldesc = _build_node_desc(reader.tree.root, '')
- self.assertEqual('\n' + fulldesc + '\n', self.simple_data.decode('ascii'))
+ self.assertEqual('\n' + fulldesc + '\n', self._nested_data.decode('ascii'))
def testSimpleYamlContentFinder(self):
- """Validate simple Yaml content search."""
+ """Validate Yaml nested content search."""
- reader = YamlReader.new_from_path(self._simple.name)
+ reader = YamlReader.new_from_path(self._nested.name)
self.assertIsNotNone(reader)
- found = reader.tree.find_node_by_path('/meta/xref')
+ found = reader.tree.find_by_path('/root/sub')
+
+ self.assertEqual(len(found), 1)
+
+ if len(found) == 1:
+ self.assertEqual(found[0].yaml_line.key, 'sub')
+
+ found = reader.tree.find_by_path('/root/sub/')
+
+ self.assertEqual(len(found), 3)
+
+ found = reader.tree.find_by_path('/root/sub/xx')
+
+ self.assertEqual(len(found), 0)
+
+ found = reader.tree.find_by_path('/root/sub/cc/i')
+
+ self.assertEqual(len(found), 1)
+
+ if len(found) == 1:
+ self.assertEqual(found[0].yaml_line.key, 'i')
+ self.assertEqual(found[0].yaml_line.is_list_item, True)
+
+ found = reader.tree.find_by_path('/root/sub/cc')
+
+ self.assertEqual(len(found), 1)
+
+ if len(found) == 1:
+
+ root = found[0]
+
+ found = root.find_by_path('cc/i')
+
+ self.assertEqual(len(found), 1)
+
+ if len(found) == 1:
+
+ self.assertEqual(found[0].yaml_line.key, 'i')
+ self.assertEqual(found[0].yaml_line.is_list_item, True)
+
+ found = root.find_by_path('/cc/i')
+
+ self.assertEqual(len(found), 1)
+
+ if len(found) == 1:
- self.assertEqual(found.yaml_line.key, 'xref')
+ self.assertEqual(found[0].yaml_line.key, 'i')
+ self.assertEqual(found[0].yaml_line.is_list_item, True)
- found = reader.tree.find_node_by_path('/meta/xref/')
+ found = root.find_by_path('//i')
- self.assertEqual(found.yaml_line.key, 'xref')
+ self.assertEqual(len(found), 1)
- found = reader.tree.find_node_by_path('/meta/xref/aa')
+ if len(found) == 1:
- self.assertIsNone(found)
+ self.assertEqual(found[0].yaml_line.key, 'i')
+ self.assertEqual(found[0].yaml_line.is_list_item, True)