/* Chrysalide - Outil d'analyse de fichiers binaires * parser.c - lecteur de contenu Yaml * * Copyright (C) 2019-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 "parser.h" #include #include #include #include #include #include "collection.h" #include "pair.h" #define SCALAR_STYLE_TO_ORIGINAL_STYLE(v) \ ({ \ YamlOriginalStyle __result; \ if (v == YAML_SINGLE_QUOTED_SCALAR_STYLE) \ __result = YOS_SINGLE_QUOTED; \ else if (v == YAML_DOUBLE_QUOTED_SCALAR_STYLE) \ __result = YOS_DOUBLE_QUOTED; \ else \ __result = YOS_PLAIN; \ __result; \ }) /* Construit la version GLib d'un noeud YAML brut. */ static GYamlPair *build_pair_from_yaml(yaml_document_t *, int, int); /* Transforme un noeud YAML brut en sa version Glib. */ static GYamlNode *translate_yaml_node(yaml_document_t *, yaml_node_t *); /****************************************************************************** * * * Paramètres : document = gestionnaire de l'ensemble des noeuds bruts. * * key = indice de la clef du noeud à convertir. * * value = indice de la valeur du noeud à convertir. * * * * Description : Construit la version GLib d'un noeud YAML brut. * * * * Retour : Noeud GLib obtenu ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GYamlPair *build_pair_from_yaml(yaml_document_t *document, int key, int value) { GYamlPair *result; /* Racine à retourner */ yaml_node_t *key_node; /* Noeud brut de la clef */ yaml_node_t *value_node; /* Noeud brut de la valeur */ GYamlNode *children; /* Collection de noeuds YAML */ result = NULL; key_node = yaml_document_get_node(document, key); assert(key_node != NULL); if (key_node->type != YAML_SCALAR_NODE) goto exit; value_node = yaml_document_get_node(document, value); assert(value_node != NULL); if (value_node->type == YAML_SCALAR_NODE) result = g_yaml_pair_new((char *)key_node->data.scalar.value, SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style), (char *)value_node->data.scalar.value, SCALAR_STYLE_TO_ORIGINAL_STYLE(value_node->data.scalar.style)); else { children = translate_yaml_node(document, value_node); if (children != NULL) { result = g_yaml_pair_new((char *)key_node->data.scalar.value, SCALAR_STYLE_TO_ORIGINAL_STYLE(key_node->data.scalar.style), NULL, YOS_PLAIN); g_yaml_pair_set_children(result, G_YAML_COLLEC(children)); } } exit: return result; } /****************************************************************************** * * * Paramètres : document = gestionnaire de l'ensemble des noeuds bruts. * * node = point de départ des transformations. * * * * Description : Transforme un noeud YAML brut en sa version Glib. * * * * Retour : Noeud GLib obtenu ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ static GYamlNode *translate_yaml_node(yaml_document_t *document, yaml_node_t *node) { GYamlNode *result; /* Racine à retourner */ yaml_node_item_t *index; /* Elément d'une série */ yaml_node_t *item; /* Elément d'une série */ GYamlNode *child; /* Version GLib de l'élément */ yaml_node_pair_t *pair; /* Combinaison clef/valeur */ GYamlPair *sub; /* Sous-noeud à intégrer */ switch (node->type) { case YAML_SCALAR_NODE: result = G_YAML_NODE(g_yaml_pair_new((char *)node->data.scalar.value, SCALAR_STYLE_TO_ORIGINAL_STYLE(node->data.scalar.style), NULL, YOS_PLAIN)); break; case YAML_SEQUENCE_NODE: result = G_YAML_NODE(g_yaml_collection_new(true)); for (index = node->data.sequence.items.start; index < node->data.sequence.items.top; index++) { item = yaml_document_get_node(document, *index); assert(item != NULL); child = translate_yaml_node(document, item); if (child == NULL) { g_clear_object(&result); break; } g_yaml_collection_add_node(G_YAML_COLLEC(result), child); } break; case YAML_MAPPING_NODE: result = G_YAML_NODE(g_yaml_collection_new(false)); for (pair = node->data.mapping.pairs.start; pair < node->data.mapping.pairs.top; pair++) { sub = build_pair_from_yaml(document, pair->key, pair->value); if (sub == NULL) { g_clear_object(&result); break; } g_yaml_collection_add_node(G_YAML_COLLEC(result), G_YAML_NODE(sub)); } break; default: assert(false); result = NULL; break; } return result; } /****************************************************************************** * * * Paramètres : text = définitions textuelles d'un contenu brut. * * len = taille de ces définitions. * * * * Description : Crée une arborescence YAML pour contenu au format adapté. * * * * Retour : Arborescence YAML mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GYamlNode *parse_yaml_from_text(const char *text, size_t len) { GYamlNode *result; /* Racine à retourner */ yaml_parser_t parser; /* Lecteur du contenu fourni */ yaml_document_t document; /* Document YAML constitué */ int ret; /* Bilan de la constitution */ yaml_node_t *root; /* Elément racine brut */ result = NULL; yaml_parser_initialize(&parser); yaml_parser_set_input_string(&parser, (const unsigned char *)text, len); ret = yaml_parser_load(&parser, &document); if (ret != 1) goto bad_loading; root = yaml_document_get_root_node(&document); if (root != NULL) result = translate_yaml_node(&document, root); yaml_document_delete(&document); bad_loading: yaml_parser_delete(&parser); return result; } /****************************************************************************** * * * Paramètres : filename = chemin vers des définitions de règles. * * * * Description : Crée une arborescence YAML pour fichier au format adapté. * * * * Retour : Arborescence YAML mise en place ou NULL en cas d'échec. * * * * Remarques : - * * * ******************************************************************************/ GYamlNode *parse_yaml_from_file(const char *filename) { GYamlNode *result; /* Racine à retourner */ GBinContent *content; /* Fichier à parcourir */ phys_t size; /* Taille du contenu associé */ vmpa2t start; /* Tête de lecture */ const bin_t *data; /* Données à consulter */ char *dumped; /* Contenu manipulable */ result = NULL; content = g_file_content_new(filename); if (content == NULL) goto no_content; size = g_binary_content_compute_size(content); g_binary_content_compute_start_pos(content, &start); data = g_binary_content_get_raw_access(content, &start, size); dumped = malloc((size + 1) * sizeof(char)); memcpy(dumped, data, size); dumped[size] = '\0'; result = parse_yaml_from_text(dumped, size); free(dumped); g_object_unref(G_OBJECT(content)); no_content: return result; }