From 459b345d69532825f21bdcd3e4f92009b0a046dc Mon Sep 17 00:00:00 2001 From: Cyrille Bagard Date: Sun, 3 Nov 2019 23:56:52 +0100 Subject: Handled sequences with the Yaml reader in an improved way. --- plugins/yaml/Makefile.am | 1 + plugins/yaml/collection.c | 312 +++++++++++++++++++++++++++++++++ plugins/yaml/collection.h | 74 ++++++++ plugins/yaml/line.c | 23 +-- plugins/yaml/line.h | 4 + plugins/yaml/node.c | 192 +++++++++++++------- plugins/yaml/node.h | 18 +- plugins/yaml/python/Makefile.am | 1 + plugins/yaml/python/collection.c | 370 +++++++++++++++++++++++++++++++++++++++ plugins/yaml/python/collection.h | 45 +++++ plugins/yaml/python/module.c | 2 + plugins/yaml/python/node.c | 168 ++++++++++++------ plugins/yaml/python/reader.c | 16 +- plugins/yaml/python/tree.c | 99 +++++------ plugins/yaml/reader.c | 12 +- plugins/yaml/tree.c | 277 ++++++++++++++--------------- plugins/yaml/tree.h | 13 +- tests/plugins/yamlrdr.py | 174 ++++++++++++++---- 18 files changed, 1407 insertions(+), 394 deletions(-) create mode 100644 plugins/yaml/collection.c create mode 100644 plugins/yaml/collection.h create mode 100644 plugins/yaml/python/collection.c create mode 100644 plugins/yaml/python/collection.h 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 . + */ + + +#include "collection.h" + + +#include + + + +/* 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 . + */ + + +#ifndef PLUGINS_YAML_COLLECTION_H +#define PLUGINS_YAML_COLLECTION_H + + +#include +#include + + +#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 +#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 + + +#include + + +#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 +#include + + + +/* 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 +#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 +#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 #include #include +#include +#include + + +#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) -- cgit v0.11.2-87-g4458