/* Chrysalide - Outil d'analyse de fichiers binaires * pair.c - noeud YAML de paire clef/valeur * * Copyright (C) 2020-2023 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "pair.h" #include #include #include #include #include "pair-int.h" /* -------------------- DEFINITIONS PROPRES POUR LE SUPPORT YAML -------------------- */ /* Initialise la classe des noeuds d'arborescence YAML. */ static void g_yaml_pair_class_init(GYamlPairClass *); /* Initialise une instance de noeud d'arborescence YAML. */ static void g_yaml_pair_init(GYamlPair *); /* Supprime toutes les références externes. */ static void g_yaml_pair_dispose(GYamlPair *); /* Procède à la libération totale de la mémoire. */ static void g_yaml_pair_finalize(GYamlPair *); /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */ /* Recherche le premier noeud correspondant à un chemin. */ static GYamlNode *g_yaml_pair_find_first_by_path(GYamlPair *, const char *); /* ---------------------------------------------------------------------------------- */ /* DEFINITIONS PROPRES POUR LE SUPPORT YAML */ /* ---------------------------------------------------------------------------------- */ /* Indique le type défini pour un noeud d'arborescence YAML. */ G_DEFINE_TYPE(GYamlPair, g_yaml_pair, G_TYPE_YAML_NODE); /****************************************************************************** * * * Paramètres : klass = classe à initialiser. * * * * Description : Initialise la classe des noeuds d'arborescence YAML. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_yaml_pair_class_init(GYamlPairClass *klass) { GObjectClass *object; /* Autre version de la classe */ GYamlNodeClass *node; /* Version parente de classe */ object = G_OBJECT_CLASS(klass); object->dispose = (GObjectFinalizeFunc/* ! */)g_yaml_pair_dispose; object->finalize = (GObjectFinalizeFunc)g_yaml_pair_finalize; node = G_YAML_NODE_CLASS(klass); node->find = (find_first_yaml_node_fc)g_yaml_pair_find_first_by_path; } /****************************************************************************** * * * Paramètres : pair = instance à initialiser. * * * * Description : Initialise une instance de noeud d'arborescence YAML. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_yaml_pair_init(GYamlPair *pair) { pair->key = NULL; pair->key_style = YOS_PLAIN; pair->value = NULL; pair->value_style = YOS_PLAIN; pair->children = NULL; } /****************************************************************************** * * * Paramètres : pair = instance d'objet GLib à traiter. * * * * Description : Supprime toutes les références externes. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_yaml_pair_dispose(GYamlPair *pair) { g_clear_object(&pair->children); G_OBJECT_CLASS(g_yaml_pair_parent_class)->dispose(G_OBJECT(pair)); } /****************************************************************************** * * * Paramètres : pair = instance d'objet GLib à traiter. * * * * Description : Procède à la libération totale de la mémoire. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ static void g_yaml_pair_finalize(GYamlPair *pair) { if (pair->key != NULL) free(pair->key); if (pair->value != NULL) free(pair->value); G_OBJECT_CLASS(g_yaml_pair_parent_class)->finalize(G_OBJECT(pair)); } /****************************************************************************** * * * Paramètres : key = désignation pour le noeud YAML. * * kstyle = format d'origine de la clef. * * value = éventuelle valeur directe portée par le noeud. * * vstyle = éventuel format d'origine de l'éventuelle valeur. * * * * Description : Construit un noeud d'arborescence YAML. * * * * Retour : Instance mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GYamlPair *g_yaml_pair_new(const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle) { GYamlPair *result; /* Structure à retourner */ result = g_object_new(G_TYPE_YAML_PAIR, NULL); if (!g_yaml_pair_create(result, key, kstyle, value, vstyle)) g_clear_object(&result); return result; } /****************************************************************************** * * * Paramètres : pair = paire YAML à initialiser pleinement. * * key = désignation pour le noeud YAML. * * kstyle = format d'origine de la clef. * * value = éventuelle valeur directe portée par le noeud. * * vstyle = éventuel format d'origine de l'éventuelle valeur. * * * * Description : Met en place une pair clef/valeur YAML. * * * * Retour : Bilan de l'opération. * * * * Remarques : - * * * ******************************************************************************/ bool g_yaml_pair_create(GYamlPair *pair, const char *key, YamlOriginalStyle kstyle, const char *value, YamlOriginalStyle vstyle) { bool result; /* Bilan à retourner */ result = true; pair->key = strdup(key); pair->key_style = kstyle; if (value != NULL) { pair->value = strdup(value); pair->value_style = vstyle; } return result; } /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à consulter. * * * * Description : Fournit la clef représentée dans une paire en YAML. * * * * Retour : Clef sous forme de chaîne de caractères. * * * * Remarques : - * * * ******************************************************************************/ const char *g_yaml_pair_get_key(const GYamlPair *pair) { char *result; /* Valeur à retourner */ result = pair->key; return result; } /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à consulter. * * * * Description : Indique le format d'origine YAML associé à la clef. * * * * Retour : Valeur renseignée lors du chargement du noeud. * * * * Remarques : - * * * ******************************************************************************/ YamlOriginalStyle g_yaml_pair_get_key_style(const GYamlPair *pair) { YamlOriginalStyle result; /* Indication à retourner */ result = pair->key_style; return result; } /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à consulter. * * * * Description : Fournit l'éventuelle valeur d'une paire en YAML. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ const char *g_yaml_pair_get_value(const GYamlPair *pair) { char *result; /* Valeur à retourner */ result = pair->value; return result; } /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à consulter. * * * * Description : Indique le format d'origine YAML associé à la valeur. * * * * Retour : Valeur renseignée lors du chargement du noeud. * * * * Remarques : - * * * ******************************************************************************/ YamlOriginalStyle g_yaml_pair_get_value_style(const GYamlPair *pair) { YamlOriginalStyle result; /* Indication à retourner */ result = pair->value_style; return result; } /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à consulter. * * * * Description : Rassemble une éventuelle séquence de valeurs attachées. * * * * Retour : Valeur sous forme de chaîne de caractères ou NULL. * * * * Remarques : - * * * ******************************************************************************/ char *g_yaml_pair_aggregate_value(const GYamlPair *pair) { char *result; /* Valeur à retourner */ GYamlNode **nodes; /* Eventuels noeuds trouvés */ size_t count; /* Quantité de ces noeuds */ size_t i; /* Boucle de parcours */ GYamlPair *child; /* Couple clef/valeur enfant */ bool failed; /* Détection d'un échec */ result = NULL; if (pair->value != NULL) result = strdup(pair->value); else if (pair->children != NULL) { if (!g_yaml_collection_is_sequence(pair->children)) goto exit; nodes = g_yaml_collection_get_nodes(pair->children, &count); if (count == 0) result = strdup("[ ]"); else { result = strdup("[ "); for (i = 0; i < count; i++) { if (!G_IS_YAML_PAIR(nodes[i])) break; child = G_YAML_PAIR(nodes[i]); if (child->value != NULL) break; if (i > 0) result = stradd(result, ", "); switch (child->key_style) { case YOS_PLAIN: result = stradd(result, child->key); break; case YOS_SINGLE_QUOTED: result = straddfmt(result, "'%s'", child->key); break; case YOS_DOUBLE_QUOTED: result = straddfmt(result, "\"%s\"", child->key); break; } g_object_unref(G_OBJECT(nodes[i])); } failed = (i < count); for (; i < count; i++) g_object_unref(G_OBJECT(nodes[i])); free(nodes); if (failed) { free(result); result = NULL; } else result = stradd(result, " ]"); } } exit: return result; } /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à compléter. * * children = collection de noeuds YAML. * * * * Description : Attache une collection de noeuds YAML à un noeud. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void g_yaml_pair_set_children(GYamlPair *pair, GYamlCollection *children) { g_clear_object(&pair->children); g_object_ref_sink(G_OBJECT(children)); pair->children = children; } /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à consulter. * * * * Description : Fournit une éventuelle collection rattachée à un noeud. * * * * Retour : Collection de noeuds YAML ou NULL. * * * * Remarques : - * * * ******************************************************************************/ GYamlCollection *g_yaml_pair_get_children(const GYamlPair *pair) { GYamlCollection *result; /* Collection à renvoyer */ result = pair->children; if (result != NULL) g_object_ref(G_OBJECT(result)); return result; } /* ---------------------------------------------------------------------------------- */ /* IMPLEMENTATION DES FONCTIONS DE CLASSE */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : pair = noeud d'arborescence YAML à consulter. * * path = chemin d'accès à parcourir. * * * * Description : Recherche le premier noeud correspondant à un chemin. * * * * Retour : Noeud avec la correspondance établie ou NULL si non trouvé. * * * * Remarques : - * * * ******************************************************************************/ static GYamlNode *g_yaml_pair_find_first_by_path(GYamlPair *pair, const char *path) { GYamlNode *result; /* Trouvaille à retourner */ char *next; /* Prochaine partie du chemin */ size_t cmplen; /* Etendue de la comparaison */ int ret; /* Bilan d'une comparaison */ assert(path[0] != '/' && path[0] != '\0'); /* Correspondance au niveau du noeud ? */ next = strchr(path, '/'); if (next == NULL) ret = strcmp(path, pair->key); else { cmplen = next - path; assert(cmplen > 0); ret = strncmp(path, pair->key, cmplen); } /* Si correspondance il y a... */ if (ret == 0) { /* ... et que la recherche se trouve en bout de parcours */ if (next == NULL) { result = G_YAML_NODE(pair); g_object_ref(G_OBJECT(result)); } /* Recherche supplémentaire dans les sous-noeuds ? */ else if (pair->children != NULL) result = g_yaml_node_find_first_by_path(G_YAML_NODE(pair->children), path + cmplen); else result = NULL; } else result = NULL; return result; }