summaryrefslogtreecommitdiff
path: root/plugins/kaitai/parsers
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/kaitai/parsers')
-rw-r--r--plugins/kaitai/parsers/Makefile.am25
-rw-r--r--plugins/kaitai/parsers/attribute-int.h107
-rw-r--r--plugins/kaitai/parsers/attribute.c2213
-rw-r--r--plugins/kaitai/parsers/attribute.h158
-rw-r--r--plugins/kaitai/parsers/enum-int.h79
-rw-r--r--plugins/kaitai/parsers/enum.c765
-rw-r--r--plugins/kaitai/parsers/enum.h76
-rw-r--r--plugins/kaitai/parsers/instance-int.h59
-rw-r--r--plugins/kaitai/parsers/instance.c503
-rw-r--r--plugins/kaitai/parsers/instance.h71
-rw-r--r--plugins/kaitai/parsers/meta-int.h60
-rw-r--r--plugins/kaitai/parsers/meta.c398
-rw-r--r--plugins/kaitai/parsers/meta.h71
-rw-r--r--plugins/kaitai/parsers/struct-int.h77
-rw-r--r--plugins/kaitai/parsers/struct.c837
-rw-r--r--plugins/kaitai/parsers/struct.h80
-rw-r--r--plugins/kaitai/parsers/switch-int.h78
-rw-r--r--plugins/kaitai/parsers/switch.c644
-rw-r--r--plugins/kaitai/parsers/switch.h61
-rw-r--r--plugins/kaitai/parsers/type-int.h58
-rw-r--r--plugins/kaitai/parsers/type.c294
-rw-r--r--plugins/kaitai/parsers/type.h65
22 files changed, 6779 insertions, 0 deletions
diff --git a/plugins/kaitai/parsers/Makefile.am b/plugins/kaitai/parsers/Makefile.am
new file mode 100644
index 0000000..c7e313b
--- /dev/null
+++ b/plugins/kaitai/parsers/Makefile.am
@@ -0,0 +1,25 @@
+
+noinst_LTLIBRARIES = libkaitaiparsers.la
+
+libkaitaiparsers_la_SOURCES = \
+ attribute-int.h \
+ attribute.h attribute.c \
+ enum-int.h \
+ enum.h enum.c \
+ instance-int.h \
+ instance.h instance.c \
+ meta-int.h \
+ meta.h meta.c \
+ struct-int.h \
+ struct.h struct.c \
+ switch-int.h \
+ switch.h switch.c \
+ type-int.h \
+ type.h type.c
+
+libkaitaiparsers_la_CFLAGS = $(TOOLKIT_CFLAGS) $(LIBXML_CFLAGS) -I$(top_srcdir)/src
+
+
+devdir = $(includedir)/chrysalide-$(subdir)
+
+dev_HEADERS = $(libkaitaiparsers_la_SOURCES:%c=)
diff --git a/plugins/kaitai/parsers/attribute-int.h b/plugins/kaitai/parsers/attribute-int.h
new file mode 100644
index 0000000..7d37af3
--- /dev/null
+++ b/plugins/kaitai/parsers/attribute-int.h
@@ -0,0 +1,107 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute-int.h - prototypes pour les spécifications internes d'un attribut Kaitai
+ *
+ * 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_KAITAI_PARSERS_ATTRIBUTE_INT_H
+#define _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H
+
+
+#include "attribute.h"
+#include "switch.h"
+#include "../parser-int.h"
+
+
+
+/* Indique l'étiquette à utiliser pour identifier un attribut. */
+typedef const char * (* get_attribute_label_fc) (const GKaitaiAttribute *);
+
+/* Spécification d'un attribut Kaitai (instance) */
+struct _GKaitaiAttribute
+{
+ GKaitaiParser parent; /* A laisser en premier */
+
+ char *raw_id; /* Identifiant Kaitai */
+ char *orig_id; /* Identifiant humain */
+
+ char *doc; /* Eventuelle documentation */
+
+ KaitaiAttributePayload payload; /* Forme de la spécialisation */
+
+ struct
+ {
+ /* KAP_FIXED_CONTENT */
+ sized_string_t fixed_content; /* Données brutes attendues */
+
+ /* KAP_BIT_FIELD_TYPE */
+ uint8_t bf_size; /* Nombre de bits visés */
+
+ /* KAP_BASIC_TYPE */
+ struct
+ {
+ BaseType basic; /* Type de base */
+
+ bool is_string; /* Renvoi vers une chaîne */
+
+ SourceEndian endian; /* Boutisme forcé ? */
+ bool has_endian; /* Présence de cette force */
+
+ };
+
+ /* KAP_USER_TYPE */
+ char *named_type; /* Type particulier */
+
+ /* KAP_DYNAMIC_TYPE */
+ GKaitaiSwitch *switchon; /* Détermination dynamique */
+
+ };
+
+ /* KAP_SIZED */
+ char *fixed_size; /* Taille déterminée */
+
+ KaitaiAttributeRepetition repetition; /* Forme de répétition */
+ char *repeat_controller; /* Indication sur la répétition*/
+
+ char *condition; /* Condition de chargement */
+
+ sized_string_t terminator; /* Marqueur de fin éventuel */
+ bool consume; /* Consommation dans le flux */
+ bool include; /* Intégration de ce marqueur */
+ bool eos_error; /* Gestion des erreurs en bout */
+
+};
+
+/* Spécification d'un attribut Kaitai (classe) */
+struct _GKaitaiAttributeClass
+{
+ GKaitaiParserClass parent; /* A laisser en premier */
+
+ get_attribute_label_fc get_label; /* Désignation d'une étiquette */
+
+};
+
+
+/* Met en place un lecteur d'attribut Kaitai. */
+bool g_kaitai_attribute_create(GKaitaiAttribute *, GYamlNode *, bool);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_INT_H */
diff --git a/plugins/kaitai/parsers/attribute.c b/plugins/kaitai/parsers/attribute.c
new file mode 100644
index 0000000..6050bb1
--- /dev/null
+++ b/plugins/kaitai/parsers/attribute.c
@@ -0,0 +1,2213 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute.c - spécification d'un attribut Kaitai
+ *
+ * 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 "attribute.h"
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <analysis/contents/restricted.h>
+#include <plugins/yaml/pair.h>
+
+
+#include "attribute-int.h"
+#include "../expression.h"
+#include "../scope.h"
+#include "../records/bits.h"
+#include "../records/empty.h"
+#include "../records/item.h"
+#include "../records/list.h"
+
+
+
+/* -------------------- CORRESPONDANCE ENTRE ATTRIBUT ET BINAIRE -------------------- */
+
+
+/* Initialise la classe des attributs de spécification Kaitai. */
+static void g_kaitai_attribute_class_init(GKaitaiAttributeClass *);
+
+/* Initialise un attribut de spécification Kaitai. */
+static void g_kaitai_attribute_init(GKaitaiAttribute *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_attribute_dispose(GKaitaiAttribute *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_attribute_finalize(GKaitaiAttribute *);
+
+/* Traduit en champ de bits une chaîne de caractères. */
+static bool g_kaitai_attribute_resolve_bit_field(GKaitaiAttribute *, const char *);
+
+/* Traduit en type concret une chaîne de caractères. */
+static bool g_kaitai_attribute_resolve_type(GKaitaiAttribute *, const char *);
+
+/* Valide la cohérence des informations portées par l'attribut. */
+static bool g_kaitai_attribute_check(const GKaitaiAttribute *);
+
+/* Copie le coeur de la définition d'un lecteur d'attribut. */
+static GKaitaiAttribute *g_kaitai_attribute_dup_for(const GKaitaiAttribute *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+/* Extrait d'un contenu une série d'octets avec terminaison. */
+static bool g_kaitai_attribute_parse_terminated_bytes(GKaitaiAttribute *, const kaitai_scope_t *, GBinContent *, vmpa2t *, GMatchRecord **);
+
+/* Détermine la zone de couverture finale d'une correspondance. */
+static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttribute *, const kaitai_scope_t *, const GBinContent *, const vmpa2t *, phys_t *, mrange_t *);
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CORRESPONDANCE ENTRE ATTRIBUT ET BINAIRE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un attribut de la spécification Kaitai. */
+G_DEFINE_TYPE(GKaitaiAttribute, g_kaitai_attribute, G_TYPE_KAITAI_PARSER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des attributs de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_class_init(GKaitaiAttributeClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_attribute_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_attribute_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_attribute_parse_content;
+
+ klass->get_label = g_kaitai_attribute_get_raw_id;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = instance à initialiser. *
+* *
+* Description : Initialise un attribut de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_init(GKaitaiAttribute *attrib)
+{
+ attrib->raw_id = NULL;
+ attrib->orig_id = NULL;
+
+ attrib->doc = NULL;
+
+ attrib->payload = KAP_UNINITIALIZED;
+
+ attrib->repetition = KAR_NO_REPETITION;
+ attrib->repeat_controller = NULL;
+
+ attrib->condition = NULL;
+
+ init_szstr(&attrib->terminator);
+ attrib->consume = true;
+ attrib->include = false;
+ attrib->eos_error = true;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_dispose(GKaitaiAttribute *attrib)
+{
+ if (attrib->payload & KAP_DYNAMIC_TYPE)
+ g_clear_object(&attrib->switchon);
+
+ G_OBJECT_CLASS(g_kaitai_attribute_parent_class)->dispose(G_OBJECT(attrib));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_attribute_finalize(GKaitaiAttribute *attrib)
+{
+ if (attrib->raw_id != NULL)
+ free(attrib->raw_id);
+
+ if (attrib->orig_id != NULL)
+ free(attrib->orig_id);
+
+ if (attrib->doc != NULL)
+ free(attrib->doc);
+
+ if (attrib->payload & KAP_FIXED_CONTENT)
+ exit_szstr(&attrib->fixed_content);
+
+ else if (attrib->payload & KAP_USER_TYPE)
+ free(attrib->named_type);
+
+ if (attrib->fixed_size != NULL)
+ free(attrib->fixed_size);
+
+ if (attrib->repeat_controller != NULL)
+ free(attrib->repeat_controller);
+
+ if (attrib->condition != NULL)
+ free(attrib->condition);
+
+ exit_szstr(&attrib->terminator);
+
+ G_OBJECT_CLASS(g_kaitai_attribute_parent_class)->finalize(G_OBJECT(attrib));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Construit un lecteur d'attribut Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiAttribute *g_kaitai_attribute_new(GYamlNode *parent)
+{
+ GKaitaiAttribute *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_ATTRIBUTE, NULL);
+
+ if (!g_kaitai_attribute_create(result, parent, false /* TODO : REMME ? */))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à initialiser pleinement.*
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* need_id = encadre la présence d'un champ "id". *
+* *
+* Description : Met en place un lecteur d'attribut Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_create(GKaitaiAttribute *attrib, GYamlNode *parent, bool need_id)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *node; /* Noeud particulier présent */
+ const char *value; /* Valeur Yaml particulière */
+ char *rebuilt_value; /* Valeur Yaml rassemblée */
+ kaitai_scope_t fake; /* Contexte de circonstance */
+ resolved_value_t bytes; /* Données brutes obtenues */
+ GYamlNode *other_node; /* Autre noeud nécessaire */
+
+ result = false;
+
+ /* Identifiant obligatoire */
+
+ node = g_yaml_node_find_first_by_path(parent, "/id");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_id;
+ }
+
+ attrib->raw_id = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ else if (need_id)
+ goto bad_id;
+
+ /* Identifiant facultatif */
+
+ node = g_yaml_node_find_first_by_path(parent, "/-orig-id");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_id;
+ }
+
+ attrib->orig_id = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Eventuelle documentation */
+
+ node = g_yaml_node_find_first_by_path(parent, "/doc");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_doc;
+ }
+
+ attrib->doc = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ contents */
+
+ node = g_yaml_node_find_first_by_path(parent, "/contents");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ rebuilt_value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node));
+
+ if (rebuilt_value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ fake.meta = NULL;
+ fake.root = NULL;
+ fake.parent = NULL;
+ fake.last = NULL;
+
+ if (!resolve_kaitai_expression_as_bytes(&fake, rebuilt_value, strlen(rebuilt_value), &bytes))
+ {
+ free(rebuilt_value);
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ free(rebuilt_value);
+
+ attrib->fixed_content = bytes.bytes;
+
+ g_object_unref(G_OBJECT(node));
+
+ attrib->payload |= KAP_FIXED_CONTENT;
+
+ }
+
+ /* Charge portée par un type */
+
+ node = g_yaml_node_find_first_by_path(parent, "/type");
+
+ if (node != NULL)
+ {
+ if (attrib->payload & KAP_FIXED_CONTENT)
+ {
+ printf("Can not handle fixed content and type definition at the same time for an attribute.\n");
+ goto bad_definition;
+ }
+
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (g_kaitai_attribute_resolve_bit_field(attrib, value))
+ attrib->payload |= KAP_BIT_FIELD_TYPE;
+
+ else if (g_kaitai_attribute_resolve_type(attrib, value))
+ attrib->payload |= KAP_BASIC_TYPE;
+
+ else
+ {
+ attrib->named_type = strdup(value);
+ attrib->payload |= KAP_USER_TYPE;
+ }
+
+ }
+
+ else
+ {
+ attrib->switchon = g_kaitai_switch_new(parent, attrib);
+ if (attrib->switchon == NULL) goto bad_definition;
+
+ attrib->payload |= KAP_DYNAMIC_TYPE;
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Répétitions contrôlées ? */
+
+ node = g_yaml_node_find_first_by_path(parent, "/repeat");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "eos") == 0)
+ attrib->repetition = KAR_END_OF_STREAM;
+
+ else if (strcmp(value, "expr") == 0)
+ {
+ other_node = g_yaml_node_find_first_by_path(parent, "/repeat-expr");
+
+ if (other_node != NULL)
+ {
+ if (G_IS_YAML_PAIR(other_node))
+ {
+ value = g_yaml_pair_get_value(G_YAML_PAIR(other_node));
+
+ if (value != NULL)
+ {
+ attrib->repetition = KAR_EXPRESSION;
+ attrib->repeat_controller = strdup(value);
+ }
+ else
+ printf("Expected repeat expression\n");
+
+ }
+
+ g_object_unref(G_OBJECT(other_node));
+
+ }
+
+ }
+
+ else if (strcmp(value, "until") == 0)
+ {
+ other_node = g_yaml_node_find_first_by_path(parent, "/repeat-until");
+
+ if (other_node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(other_node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(other_node));
+
+ if (value != NULL)
+ {
+ attrib->repetition = KAR_UNTIL;
+ attrib->repeat_controller = strdup(value);
+ }
+ else
+ printf("Expected repeat expression\n");
+
+ }
+
+ g_object_unref(G_OBJECT(other_node));
+
+ }
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Intégration sous condition ? */
+
+ node = g_yaml_node_find_first_by_path(parent, "/if");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ attrib->condition = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Taille fixée ? */
+
+ node = g_yaml_node_find_first_by_path(parent, "/size");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ attrib->fixed_size = strdup(value);
+ attrib->payload |= KAP_SIZED;
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ if ((attrib->payload & KAP_SIZED) == 0)
+ goto bad_content;
+
+ }
+
+ /* Prise en considération d'une taille maximale */
+
+ node = g_yaml_node_find_first_by_path(parent, "/size-eos");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL && strcmp(value, "true") == 0)
+ {
+ if (attrib->payload != KAP_UNINITIALIZED)
+ /* printf warning */;
+
+ attrib->payload |= KAP_SIZED_EOS;
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ terminator */
+
+ node = g_yaml_node_find_first_by_path(parent, "/terminator");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ rebuilt_value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node));
+
+ if (rebuilt_value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ fake.meta = NULL;
+ fake.root = NULL;
+ fake.parent = NULL;
+ fake.last = NULL;
+
+ if (!resolve_kaitai_expression_as_bytes(&fake, rebuilt_value, strlen(rebuilt_value), &bytes))
+ {
+ free(rebuilt_value);
+ g_object_unref(G_OBJECT(node));
+ goto bad_content;
+ }
+
+ free(rebuilt_value);
+
+ if (attrib->terminator.data != NULL)
+ printf("A ending content has already been specified (implicitly by the strz type)");
+
+ else
+ {
+ attrib->terminator.data = bytes.bytes.data;
+ attrib->terminator.len = bytes.bytes.len;
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ consume */
+
+ node = g_yaml_node_find_first_by_path(parent, "/consume");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "true") == 0)
+ attrib->consume = true;
+
+ else if (strcmp(value, "false") == 0)
+ attrib->consume = false;
+
+ else
+ printf("Unsupported value for the 'consume' property (expecting true of false)");
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ include */
+
+ node = g_yaml_node_find_first_by_path(parent, "/include");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "true") == 0)
+ attrib->include = true;
+
+ else if (strcmp(value, "false") == 0)
+ attrib->include = false;
+
+ else
+ printf("Unsupported value for the 'include' property (expecting true of false)");
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Champ eos-error */
+
+ node = g_yaml_node_find_first_by_path(parent, "/eos-error");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ if (strcmp(value, "true") == 0)
+ attrib->eos_error = true;
+
+ if (strcmp(value, "false") == 0)
+ attrib->eos_error = false;
+
+ else
+ printf("Unsupported value for the 'eos_error' property (expecting true of false)");
+
+ }
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Validation finale */
+
+ result = g_kaitai_attribute_check(attrib);
+
+ bad_definition:
+
+ bad_doc:
+ bad_id:
+ bad_content:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = attribut Kaitai en cours de constitution. *
+* desc = chaîne de caractère à interpréter en type. *
+* *
+* Description : Traduit en champ de bits une chaîne de caractères. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_resolve_bit_field(GKaitaiAttribute *attrib, const char *desc)
+{
+ bool result; /* Bilan à retourner */
+ size_t len; /* Taille de la chaîne à lire */
+ char *end; /* Prochain caractère à lire */
+ unsigned long size; /* Taille du champ de bits */
+
+ result = false;
+
+ if (desc[0] == 'b')
+ {
+ len = strlen(desc);
+
+ size = strtoul(&desc[1], &end, 10);
+
+ if (size > 64)
+ {
+ printf("Unsupported size for bit field: %lu\n", size);
+ goto exit;
+ }
+
+ result = ((desc + len) == end);
+
+ if (result)
+ attrib->bf_size = size;
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = attribut Kaitai en cours de constitution. *
+* desc = chaîne de caractère à interpréter en type. *
+* *
+* Description : Traduit en type concret une chaîne de caractères. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_resolve_type(GKaitaiAttribute *attrib, const char *desc)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ attrib->basic = BTP_INVALID;
+ attrib->has_endian = false;
+
+ /**
+ * Cf. définition des types de base existants :
+ * http://doc.kaitai.io/user_guide.html#_fixed_size_structures
+ */
+
+#define RESOLVE_ENDIAN \
+ if (desc[2] == 'l') \
+ { \
+ if (desc[3] == 'e') \
+ { \
+ attrib->endian = SRE_LITTLE; \
+ attrib->has_endian = true; \
+ } \
+ } \
+ else if (desc[2] == 'b') \
+ { \
+ if (desc[3] == 'e') \
+ { \
+ attrib->endian = SRE_BIG; \
+ attrib->has_endian = true; \
+ } \
+ } \
+
+ /* Analyse de la chaîne fournie */
+
+ switch (desc[0])
+ {
+ case 'f':
+ switch (desc[1])
+ {
+ case '4':
+ attrib->basic = BTP_754R_32;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '8':
+ attrib->basic = BTP_754R_64;
+ RESOLVE_ENDIAN;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+ break;
+
+ case 's':
+ switch (desc[1])
+ {
+ case '1':
+ attrib->basic = BTP_CHAR;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '2':
+ attrib->basic = BTP_SHORT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '4':
+ attrib->basic = BTP_INT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '8':
+ attrib->basic = BTP_LONG_LONG;
+ RESOLVE_ENDIAN;
+ break;
+
+ case 't':
+ if (desc[2] == 'r')
+ {
+ attrib->basic = BTP_CHAR;
+ attrib->is_string = true;
+ if (desc[3] == 'z')
+ {
+ attrib->terminator.data = strdup("");
+ attrib->terminator.len = 1;
+ }
+ }
+ else
+ result = false;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+ break;
+
+ case 'u':
+ switch (desc[1])
+ {
+ case '1':
+ attrib->basic = BTP_UCHAR;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '2':
+ attrib->basic = BTP_USHORT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '4':
+ attrib->basic = BTP_UINT;
+ RESOLVE_ENDIAN;
+ break;
+
+ case '8':
+ attrib->basic = BTP_ULONG_LONG;
+ RESOLVE_ENDIAN;
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+ break;
+
+ default:
+ result = false;
+ break;
+
+ }
+
+ /* Vérification d'une comparaison complète */
+ if (result)
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ if (attrib->is_string)
+ {
+ if (attrib->terminator.data != NULL)
+ result = (desc[4] == 0);
+ else
+ result = (desc[3] == 0);
+ }
+ else
+ {
+ if (attrib->has_endian)
+ result = (desc[4] == 0);
+ else
+ result = (desc[2] == 0);
+ }
+ break;
+
+ default:
+ if (attrib->has_endian)
+ result = (desc[4] == 0);
+ else
+ result = (desc[2] == 0);
+ break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = attribut Kaitai à valider. *
+* *
+* Description : Valide la cohérence des informations portées par l'attribut. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_check(const GKaitaiAttribute *attrib)
+{
+ bool result; /* Bilan à retourner */
+
+ result = true;
+
+ /**
+ * Une lecture de tous les octets restants ne doit correspondre qu'à des octets bruts.
+ */
+ if (attrib->payload & KAP_SIZED_EOS && attrib->payload != KAP_SIZED_EOS)
+ {
+ result = (attrib->payload & KAP_BASIC_TYPE) && attrib->is_string;
+
+ if (!result)
+ {
+ printf("Reading all the remaining bytes should only produce bytes.");
+ result = true;
+ }
+
+ }
+
+ /**
+ * Une chaîne (type str[z]) doit comporter une séquence de terminaison.
+ */
+ if ((attrib->payload & KAP_BASIC_TYPE) && attrib->is_string)
+ {
+ result = (attrib->terminator.data != NULL) || (attrib->payload & (KAP_SIZED | KAP_SIZED_EOS));
+
+ if (!result)
+ {
+ printf("An unsized string (str type with no size attribute) has to be link to a terminator sequence.");
+ goto exit;
+ }
+
+ }
+
+ /**
+ * Si une séquence d'octets finaux est spécifiée, alors l'attribut
+ * doit correspondre à un type str[z] (lecture) ou de taille fixée
+ * (validation post-lecture).
+ */
+ if (attrib->terminator.data != NULL)
+ {
+ result = ((attrib->payload & ~(KAP_FIXED_CONTENT | KAP_BASIC_TYPE | KAP_SIZED)) == 0);
+
+ if (result && (attrib->payload & KAP_BASIC_TYPE))
+ result = attrib->is_string;
+
+ if (!result)
+ {
+ printf("A useless terminator is specified.");
+ result = true;
+ goto exit;
+ }
+
+ }
+
+ /**
+ * Il n'est pas possible d'inclure un marqueur de fin sans le consommer.
+ */
+ if (!attrib->consume && attrib->include)
+ {
+ result = false;
+ printf("It is not possible to include a terminator without consuming it.");
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à dupliquer. *
+* type = type utilisateur à associer au nouvel attribut. *
+* *
+* Description : Dérive un lecteur d'attribut Kaitai pour un type utilisateur.*
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiAttribute *g_kaitai_attribute_dup_for_user_type(const GKaitaiAttribute *attrib, const char *type)
+{
+ GKaitaiAttribute *result; /* Structure à retourner */
+
+ result = g_kaitai_attribute_dup_for(attrib);
+
+ result->payload = KAP_USER_TYPE;
+
+ result->named_type = strdup(type);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à dupliquer. *
+* *
+* Description : Copie le coeur de la définition d'un lecteur d'attribut. *
+* *
+* Retour : Nouvelle instance à compléter. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static GKaitaiAttribute *g_kaitai_attribute_dup_for(const GKaitaiAttribute *attrib)
+{
+ GKaitaiAttribute *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_ATTRIBUTE, NULL);
+
+ /**
+ * Il n'y a rien à copier dans la structure parente.
+ *
+ * Les travaux de copie ne portent ainsi que sur le présent attribut.
+ */
+
+ if (attrib->raw_id != NULL)
+ result->raw_id = strdup(attrib->raw_id);
+
+ if (attrib->orig_id != NULL)
+ result->orig_id = strdup(attrib->orig_id);
+
+ if (attrib->doc != NULL)
+ result->doc = strdup(attrib->doc);
+
+ if (attrib->fixed_size != NULL)
+ result->fixed_size = strdup(attrib->fixed_size);
+
+ result->repetition = attrib->repetition;
+
+ if (attrib->repeat_controller != NULL)
+ result->repeat_controller = strdup(attrib->repeat_controller);
+
+ if (attrib->condition != NULL)
+ result->condition = strdup(attrib->condition);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique l'étiquette à utiliser pour identifier un attribut. *
+* *
+* Retour : Valeur brute de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_label(const GKaitaiAttribute *attrib)
+{
+ const char *result; /* Valeur à renvoyer */
+ GKaitaiAttributeClass *class; /* Classe de l'instance */
+
+ class = G_KAITAI_ATTRIBUTE_GET_CLASS(attrib);
+
+ result = class->get_label(attrib);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique la désignation brute d'un identifiant Kaitai. *
+* *
+* Retour : Valeur brute de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_raw_id(const GKaitaiAttribute *attrib)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = attrib->raw_id;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique la désignation originelle d'un identifiant Kaitai. *
+* *
+* Retour : Valeur originelle de l'identifiant. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_original_id(const GKaitaiAttribute *attrib)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = attrib->orig_id;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Fournit une éventuelle documentation concernant l'attribut. *
+* *
+* Retour : Description enregistrée ou NULL si absente. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_attribute_get_doc(const GKaitaiAttribute *attrib)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = attrib->doc;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Indique la nature de la charge représentée par l'attribut. *
+* *
+* Retour : Forme de contenu représenté par le lecteur d'attribut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+KaitaiAttributePayload g_kaitai_attribute_get_payload(const GKaitaiAttribute *attrib)
+{
+ KaitaiAttributePayload result; /* Type de charge à renvoyer */
+
+ result = attrib->payload;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* basic = type de base Kaitai reconnu par le lecteur. [OUT]*
+* is_string = nature du type BTP_CHAR en sortie. [OUT] *
+* *
+* Description : Précise un éventuel type de base reconnu par le lecteur. *
+* *
+* Retour : Validité du type renseigné en argument. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_get_basic_type(const GKaitaiAttribute *attrib, BaseType *basic, bool *is_string)
+{
+ bool result; /* Validité à retourner */
+
+ result = (attrib->payload & KAP_BASIC_TYPE);
+
+ if (result)
+ {
+ *basic = attrib->basic;
+ *is_string = attrib->is_string;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* content = contenu binaire à venir lire. *
+* range = espace disponible pour la lecture. *
+* out = tableau d'octets retournés. [OUT] *
+* len = taille de ce tableau alloué. [OUT] *
+* *
+* Description : Lit les octets d'une chaîne représentée. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_read_truncated_bytes(const GKaitaiAttribute *attrib, const GBinContent *content, const mrange_t *range, bin_t **out, size_t *len)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t tmppos; /* Localisation modifiable */
+ const bin_t *data; /* Accès aux données brutes */
+
+ result = false;
+
+ if ((attrib->payload & KAP_SIZED) == 0)
+ goto bad_type;
+
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ *len = get_mrange_length(range);
+
+ data = g_binary_content_get_raw_access(content, &tmppos, *len);
+
+ *out = malloc(sizeof(bin_t) * (*len + 1));
+
+ memcpy(*out, data, *len);
+ (*out)[*len] = '\0';
+
+ result = true;
+
+ bad_type:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* *
+* Description : Détermine si l'attribue porte une valeur entière signée. *
+* *
+* Retour : Bilan de la consultation : true si un entier signé est visé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_handle_signed_integer(const GKaitaiAttribute *attrib)
+{
+ bool result; /* Bilan à retourner */
+
+ result = false;
+
+ if ((attrib->payload & KAP_BASIC_TYPE) == 0)
+ goto bad_type;
+
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ case BTP_SHORT:
+ case BTP_INT:
+ case BTP_LONG_LONG:
+ result = true;
+ break;
+
+ default:
+ break;
+
+ }
+
+ bad_type:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* content = contenu binaire à venir lire. *
+* range = espace de lecture. *
+* endian = boustime des données à respecter. *
+* out = valeur à sauvegarder sous une forme générique.[OUT]*
+* *
+* Description : Lit la valeur d'un élément Kaitai entier représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_read_value(const GKaitaiAttribute *attrib, const GBinContent *content, const mrange_t *range, SourceEndian endian, resolved_value_t *out)
+{
+ bool result; /* Bilan à retourner */
+ vmpa2t tmppos; /* Localisation modifiable */
+ const bin_t *data; /* Données brutes restituées */
+ int8_t stmp8; /* Valeur de 8 bits lue */
+ uint8_t tmp8; /* Valeur de 8 bits lue */
+ int16_t stmp16; /* Valeur de 16 bits lue */
+ uint16_t tmp16; /* Valeur de 16 bits lue */
+ int32_t stmp32; /* Valeur de 32 bits lue */
+ uint32_t tmp32; /* Valeur de 32 bits lue */
+ int64_t stmp64; /* Valeur de 64 bits lue */
+ uint64_t tmp64; /* Valeur de 64 bits lue */
+
+ result = false;
+
+ if (attrib->payload & (KAP_FIXED_CONTENT | KAP_SIZED | KAP_SIZED_EOS))
+ {
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ data = g_binary_content_get_raw_access(content, &tmppos, get_mrange_length(range));
+ result = (data != NULL);
+
+ if (result)
+ {
+ out->type = GVT_BYTES;
+
+ out->bytes.len = get_mrange_length(range);
+
+ out->bytes.data = malloc(out->bytes.len);
+ memcpy(out->bytes.data, data, out->bytes.len);
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_BASIC_TYPE)
+ {
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ if (attrib->is_string)
+ {
+ copy_vmpa(&tmppos, get_mrange_addr(range));
+
+ data = g_binary_content_get_raw_access(content, &tmppos, get_mrange_length(range));
+ result = (data != NULL);
+
+ if (result)
+ {
+ out->type = GVT_BYTES;
+
+ out->bytes.len = get_mrange_length(range);
+
+ out->bytes.data = malloc(out->bytes.len);
+ memcpy(out->bytes.data, data, out->bytes.len);
+
+ }
+
+ }
+ else
+ {
+ assert(get_mrange_length(range) == 1);
+ result = g_binary_content_read_s8(content, &tmppos, &stmp8);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp8;
+ }
+ break;
+
+ case BTP_UCHAR:
+ assert(get_mrange_length(range) == 1);
+ result = g_binary_content_read_u8(content, &tmppos, &tmp8);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp8;
+ break;
+
+ case BTP_SHORT:
+ assert(get_mrange_length(range) == 2);
+ result = g_binary_content_read_s16(content, &tmppos, endian, &stmp16);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp16;
+ break;
+
+ case BTP_USHORT:
+ assert(get_mrange_length(range) == 2);
+ result = g_binary_content_read_u16(content, &tmppos, endian, &tmp16);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp16;
+ break;
+
+ case BTP_INT:
+ assert(get_mrange_length(range) == 4);
+ result = g_binary_content_read_s32(content, &tmppos, endian, &stmp32);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp32;
+ break;
+
+ case BTP_UINT:
+ assert(get_mrange_length(range) == 4);
+ result = g_binary_content_read_u32(content, &tmppos, endian, &tmp32);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp32;
+ break;
+
+ case BTP_LONG_LONG:
+ assert(get_mrange_length(range) == 8);
+ result = g_binary_content_read_s64(content, &tmppos, endian, &stmp64);
+ out->type = GVT_SIGNED_INTEGER;
+ out->signed_integer = stmp64;
+ break;
+
+ case BTP_ULONG_LONG:
+ assert(get_mrange_length(range) == 8);
+ result = g_binary_content_read_u64(content, &tmppos, endian, &tmp64);
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp64;
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = lecteur d'attribut Kaitai à consulter. *
+* content = contenu binaire à venir lire. *
+* epos = tête de lecture avec granularité en bits. *
+* size = quantité de bits à prendre en compte. *
+* endian = boustime des données à respecter. *
+* out = valeur à sauvegarder sous une forme générique.[OUT]*
+* *
+* Description : Lit la valeur d'un champ de bits Kaitai représenté. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_attribute_read_bit_field_value(const GKaitaiAttribute *attrib, const GBinContent *content, const ext_vmpa_t *epos, uint8_t size, SourceEndian endian, resolved_value_t *out)
+{
+ bool result; /* Bilan à retourner */
+ ext_vmpa_t tmpepos; /* Localisation modifiable */
+ uint64_t tmp64; /* Valeur de 64 bits lue */
+
+ result = false;
+
+ if (attrib->payload & KAP_BIT_FIELD_TYPE)
+ {
+ copy_evmpa(&tmpepos, epos);
+
+ result = g_binary_content_read_bits(content, &tmpepos, size, endian, &tmp64);
+
+ if (result)
+ {
+ out->type = GVT_UNSIGNED_INTEGER;
+ out->unsigned_integer = tmp64;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ resolved_value_t authorized; /* Validation des traitements */
+
+ mrange_t work_range; /* Définition de cette aire */
+ GBinContent *work_area; /* Aire de travail */
+ bool has_empty_size; /* Mémorise une taille nulle */
+
+
+ //unsigned long long value; /* Valeur entière finale */
+ //bool status; /* Bilan d'une conversion */
+
+
+ vmpa2t tmp; /* Position de travail */
+ phys_t diff; /* Différentiel de positions */
+ resolved_value_t resolved; /* Valeur entière obtenue */
+ phys_t max_size; /* Taille maximale imposée */
+
+
+ const bin_t *data; /* Données à comparer */
+ GKaitaiType *user_type; /* Définition particulière */
+
+
+ mrange_t range; /* Couverture appliquée */
+ SourceEndian endian; /* Boutisme à observer */
+ phys_t cur_diff; /* Avancée de lecture courante */
+
+
+ result = false;
+ *record = NULL;
+
+ /* Lecture soumise à condition ? */
+
+ if (attrib->condition != NULL)
+ {
+ result = resolve_kaitai_expression_as_boolean(locals,
+ attrib->condition,
+ strlen(attrib->condition),
+ &authorized);
+
+ if (!result || !authorized.status)
+ goto exit;
+
+ }
+
+ /* Zone de travail restreinte */
+
+ g_binary_content_compute_end_pos(content, &tmp);
+ diff = compute_vmpa_diff(&epos->base, &tmp);
+
+ if (epos->consumed_extra_bits > 0 && diff > 0)
+ diff--;
+
+ if (attrib->payload & KAP_SIZED)
+ {
+ result = resolve_kaitai_expression_as_integer(locals,
+ attrib->fixed_size,
+ strlen(attrib->fixed_size),
+ &resolved);
+
+ if (result)
+ {
+ if (resolved.type == GVT_UNSIGNED_INTEGER)
+ max_size = resolved.unsigned_integer;
+ else
+ {
+ assert(resolved.type == GVT_SIGNED_INTEGER);
+
+ if (resolved.signed_integer < 0)
+ result = false;
+ else
+ max_size = resolved.signed_integer;
+
+ }
+
+ if (result)
+ result = (diff >= max_size);
+
+ if (!result)
+ printf("Need more data!\n");
+
+ if (result && max_size < diff)
+ diff = max_size;
+
+ }
+
+ if (!result)
+ goto exit;
+
+ align_evmpa_on_byte(epos);
+
+ init_mrange(&work_range, &epos->base, diff);
+ work_area = g_restricted_content_new(content, &work_range);
+
+ has_empty_size = (diff == 0);
+
+ }
+ else
+ {
+ work_area = content;
+ has_empty_size = false;
+ }
+
+ /* Etablissement d'une zone de correspondance */
+
+ if (attrib->payload == KAP_UNINITIALIZED)
+ assert(false);
+
+ else if (attrib->payload & KAP_SIZED_EOS)
+ {
+ align_evmpa_on_byte(epos);
+ result = true;
+ }
+
+ else if (attrib->payload & KAP_FIXED_CONTENT)
+ {
+ if (diff >= attrib->fixed_content.len)
+ {
+ align_evmpa_on_byte(epos);
+
+ copy_vmpa(&tmp, &epos->base);
+
+ data = g_binary_content_get_raw_access(work_area, &tmp, attrib->fixed_content.len);
+ assert(data != NULL);
+
+ result = (memcmp(data, attrib->fixed_content.data, attrib->fixed_content.len) == 0);
+
+ if (result)
+ diff = attrib->fixed_content.len;
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_BIT_FIELD_TYPE)
+ {
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = g_record_bit_field_new(attrib, work_area, epos, attrib->bf_size, endian);
+
+ result = (*record != NULL);
+
+ if (result)
+ advance_evmpa_bits(epos, attrib->bf_size);
+
+ }
+
+ else if (attrib->payload & KAP_BASIC_TYPE)
+ {
+ align_evmpa_on_byte(epos);
+
+ switch (attrib->basic)
+ {
+ case BTP_CHAR:
+ case BTP_UCHAR:
+ if (attrib->is_string)
+ {
+ if ((attrib->payload & KAP_SIZED) == 0)
+ result = g_kaitai_attribute_parse_terminated_bytes(attrib, locals,
+ work_area, &epos->base, record);
+ }
+ else
+ {
+ result = (diff >= 1);
+ diff = 1;
+ }
+ break;
+
+ case BTP_SHORT:
+ case BTP_USHORT:
+ result = (diff >= 2);
+ diff = 2;
+ break;
+
+ case BTP_INT:
+ case BTP_UINT:
+ case BTP_754R_32:
+ result = (diff >= 4);
+ diff = 4;
+ break;
+
+ case BTP_LONG_LONG:
+ case BTP_ULONG_LONG:
+ case BTP_754R_64:
+ result = (diff >= 8);
+ diff = 8;
+ break;
+
+ default:
+ break;
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_USER_TYPE)
+ {
+ user_type = find_sub_type(locals, attrib->named_type);
+
+ if (user_type != NULL)
+ {
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(user_type),
+ locals, work_area, epos, record);
+
+ if (result)
+ /**
+ * Le type utilisateur dérive du type GKaitaiStruct, qui ne possède pas
+ * d'identifiant propre. La correspondance produite est ainsi nominalement
+ * anonyme, ce qui empêche toute résolution.
+ *
+ * Le rattachement de l'étiquette de l'attribut d'origine est donc forcée ici.
+ */
+ g_match_record_fix_creator(*record, G_KAITAI_PARSER(attrib));
+
+
+ g_object_unref(G_OBJECT(user_type));
+
+ }
+
+ }
+
+ else if (attrib->payload & KAP_DYNAMIC_TYPE)
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib->switchon), locals, work_area, epos, record);
+
+ else if (attrib->payload & KAP_SIZED)
+ {
+ /* Cas déjà traité en début de fonction */
+
+ }
+
+ /* Enregistrement de la correspondance */
+
+ if (result && *record == NULL)
+ {
+ /**
+ * A ce stade, la granularité des travaux est l'octet.
+ */
+ assert(epos->consumed_extra_bits == 0);
+
+ /**
+ * On choisit de laisser la création de correspondances nulles.
+ *
+ * Cela permet de disposer de la présence de champs valides, même vides
+ * (cf. "4.10.3. Repeat until condition is met")
+ */
+
+ /* if (diff > 0) */
+ {
+ result = g_kaitai_attribute_compute_maybe_terminated_range(attrib, locals, content,
+ &epos->base, &diff, &range);
+
+ if (result)
+ {
+ if (has_empty_size)
+ *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(attrib), content, &epos->base));
+
+ else
+ {
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = G_MATCH_RECORD(g_record_item_new(attrib, work_area, &range, endian));
+
+ if (*record != NULL)
+ advance_vmpa(&epos->base, diff);
+ else
+ result = false;
+
+ }
+
+ }
+
+ }
+
+ }
+
+ /* Libération de zone de travail restreinte ? */
+
+ if (attrib->payload & KAP_SIZED)
+ {
+ /* Réalignement éventuel suite aux lectures dans la zone périmétrée... */
+ align_evmpa_on_byte(epos);
+
+ cur_diff = compute_vmpa_diff(get_mrange_addr(&work_range), &epos->base);
+
+ /* Pour GCC... */
+ max_size = get_mrange_length(&work_range);
+
+ if (cur_diff < max_size)
+ advance_vmpa(&epos->base, max_size - cur_diff);
+
+ assert(work_area != content);
+ g_object_unref(G_OBJECT(work_area));
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* pos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Extrait d'un contenu une série d'octets avec terminaison. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_parse_terminated_bytes(GKaitaiAttribute *attrib, const kaitai_scope_t *locals, GBinContent *content, vmpa2t *pos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t marker; /* Marqueur potentiel à tester */
+ vmpa2t iter; /* Tête de lecture courante */
+ vmpa2t end; /* Fin du parcours possible */
+ vmpa2t tmp; /* Position à mouvante */
+ phys_t diff; /* Avancée de lecture courante */
+ mrange_t range; /* Couverture appliquée */
+ SourceEndian endian; /* Boutisme à observer */
+
+ result = false;
+
+ /* Recherche du marqueur de fin */
+
+ marker.len = attrib->terminator.len;
+
+ copy_vmpa(&iter, pos);
+ g_binary_content_compute_end_pos(content, &end);
+
+ while (cmp_vmpa_by_phy(&iter, &end) < 0)
+ {
+ copy_vmpa(&tmp, &iter);
+
+ marker.data = (char *)g_binary_content_get_raw_access(content, &tmp, marker.len);
+ if (marker.data == NULL) break;
+
+ if (szmemcmp(&marker, &attrib->terminator) == 0)
+ {
+ result = true;
+ break;
+ }
+
+ advance_vmpa(&iter, 1);
+
+ }
+
+ /* Si la recherche a abouti */
+
+ if (result)
+ {
+ diff = compute_vmpa_diff(pos, &iter);
+
+ if (attrib->include)
+ diff += marker.len;
+
+ init_mrange(&range, pos, diff);
+
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = G_MATCH_RECORD(g_record_item_new(attrib, content, &range, endian));
+
+ copy_vmpa(pos, &iter);
+
+ if (attrib->consume)
+ advance_vmpa(pos, marker.len);
+
+ }
+
+ /* Sinon l'absence de marqueur est-elle tolérée ? */
+
+ else if (!attrib->eos_error)
+ {
+ diff = compute_vmpa_diff(pos, &end);
+
+ init_mrange(&range, pos, diff);
+
+ if (attrib->has_endian)
+ endian = attrib->endian;
+ else
+ endian = g_kaitai_meta_get_endian(locals->meta);
+
+ *record = G_MATCH_RECORD(g_record_item_new(attrib, content, &range, endian));
+
+ copy_vmpa(pos, &end);
+
+ result = true;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* pos = tête de lecture courante. *
+* maxsize = taille maximale de la zone de correspondance. [OUT]*
+* range = zone de couverture à officialiser. [OUT] *
+* *
+* Description : Détermine la zone de couverture finale d'une correspondance. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttribute *attrib, const kaitai_scope_t *locals, const GBinContent *content, const vmpa2t *pos, phys_t *maxsize, mrange_t *range)
+{
+ bool result; /* Bilan à retourner */
+ sized_string_t marker; /* Marqueur potentiel à tester */
+ vmpa2t iter; /* Tête de lecture courante */
+ vmpa2t end; /* Fin du parcours possible */
+ vmpa2t tmp; /* Position à mouvante */
+ phys_t diff; /* Avancée de lecture courante */
+
+ if (attrib->terminator.data == NULL)
+ {
+ init_mrange(range, pos, *maxsize);
+ result = true;
+ }
+
+ else
+ {
+ result = false;
+
+ if (attrib->terminator.len > *maxsize)
+ goto exit;
+
+ /* Recherche du marqueur de fin */
+
+ marker.len = attrib->terminator.len;
+
+ copy_vmpa(&iter, pos);
+
+ copy_vmpa(&tmp, pos);
+ advance_vmpa(&tmp, *maxsize - marker.len);
+
+ while (cmp_vmpa_by_phy(&iter, &end) <= 0)
+ {
+ copy_vmpa(&tmp, &iter);
+
+ marker.data = (char *)g_binary_content_get_raw_access(content, &tmp, marker.len);
+ if (marker.data == NULL) break;
+
+ if (szmemcmp(&marker, &attrib->terminator) == 0)
+ {
+ result = true;
+ break;
+ }
+
+ advance_vmpa(&iter, 1);
+
+ }
+
+ /* Si la recherche a abouti */
+
+ if (result)
+ {
+ diff = compute_vmpa_diff(pos, &iter);
+
+ if (attrib->include)
+ init_mrange(range, pos, diff + marker.len);
+ else
+ init_mrange(range, pos, diff);
+
+ assert((diff + marker.len) <= *maxsize);
+
+ if (attrib->consume)
+ *maxsize = diff + marker.len;
+ else
+ *maxsize = diff;
+
+ }
+
+ /* Sinon l'absence de marqueur est-elle tolérée ? */
+
+ else if (!attrib->eos_error)
+ {
+ init_mrange(range, pos, *maxsize);
+ result = true;
+ }
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : attrib = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ resolved_value_t authorized; /* Validation des traitements */
+ GRecordList *list; /* Constitution d'une liste */
+ vmpa2t end; /* Position maximale du flux */
+ phys_t diff; /* Différentiel de positions */
+ GMatchRecord *child; /* Element de liste à intégrer */
+ resolved_value_t resolved; /* Valeur entière obtenue */
+ unsigned long long count; /* Nombre d'itérations à mener */
+ unsigned long long i; /* Boucle de parcours */
+ resolved_value_t loop; /* Poursuite des lectures ? */
+
+ if (attrib->repetition == KAR_NO_REPETITION)
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, record);
+
+ else
+ {
+ /* Lecture soumise à condition ? */
+
+ if (attrib->condition != NULL)
+ {
+ result = resolve_kaitai_expression_as_boolean(locals,
+ attrib->condition,
+ strlen(attrib->condition),
+ &authorized);
+
+ if (!result || !authorized.status)
+ goto exit;
+
+ }
+
+ list = g_record_list_new(attrib, content, &epos->base);
+
+ switch (attrib->repetition)
+ {
+ case KAR_END_OF_STREAM:
+
+ result = true;
+
+ g_binary_content_compute_end_pos(content, &end);
+ diff = compute_vmpa_diff(&epos->base, &end);
+
+ while (diff > 0)
+ {
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
+ if (!result) break;
+
+ g_record_list_add_record(list, child);
+ remember_last_record(locals, child);
+
+ diff = compute_vmpa_diff(&epos->base, &end);
+
+ }
+
+ break;
+
+ case KAR_EXPRESSION:
+
+ result = resolve_kaitai_expression_as_integer(locals,
+ attrib->repeat_controller,
+ strlen(attrib->repeat_controller),
+ &resolved);
+
+ if (resolved.type == GVT_UNSIGNED_INTEGER)
+ count = resolved.unsigned_integer;
+ else
+ {
+ assert(resolved.type == GVT_SIGNED_INTEGER);
+
+ if (resolved.signed_integer < 0)
+ {
+ result = false;
+ break;
+ }
+
+ count = resolved.signed_integer;
+
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
+ if (!result) break;
+
+ g_record_list_add_record(list, child);
+ remember_last_record(locals, child);
+
+ }
+
+ break;
+
+ case KAR_UNTIL:
+
+ do
+ {
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
+ if (!result) break;
+
+ g_record_list_add_record(list, child);
+ remember_last_record(locals, child);
+
+ result = resolve_kaitai_expression_as_boolean(locals,
+ attrib->repeat_controller,
+ strlen(attrib->repeat_controller),
+ &loop);
+ if (!result) break;
+
+ }
+ while (!loop.status);
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (!result) g_clear_object(&list);
+
+ *record = G_MATCH_RECORD(list);
+
+ }
+
+ exit:
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/attribute.h b/plugins/kaitai/parsers/attribute.h
new file mode 100644
index 0000000..9b43936
--- /dev/null
+++ b/plugins/kaitai/parsers/attribute.h
@@ -0,0 +1,158 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * attribute.h - prototypes pour la spécification d'un attribut Kaitai
+ *
+ * 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_KAITAI_PARSERS_ATTRIBUTE_H
+#define _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <analysis/content.h>
+#include <analysis/types/basic.h>
+#include <plugins/yaml/node.h>
+
+
+#include "../expression.h"
+
+
+
+#define G_TYPE_KAITAI_ATTRIBUTE g_kaitai_attribute_get_type()
+#define G_KAITAI_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttribute))
+#define G_IS_KAITAI_ATTRIBUTE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ATTRIBUTE))
+#define G_KAITAI_ATTRIBUTE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttributeClass))
+#define G_IS_KAITAI_ATTRIBUTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ATTRIBUTE))
+#define G_KAITAI_ATTRIBUTE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ATTRIBUTE, GKaitaiAttributeClass))
+
+
+/* Spécification d'un attribut Kaitai (instance) */
+typedef struct _GKaitaiAttribute GKaitaiAttribute;
+
+/* Spécification d'un attribut Kaitai (classe) */
+typedef struct _GKaitaiAttributeClass GKaitaiAttributeClass;
+
+
+/* Type de charge associée à un attribut */
+typedef enum _KaitaiAttributePayload
+{
+ KAP_UNINITIALIZED = (0 << 0), /* Type non initialisé */
+
+ KAP_FIXED_CONTENT = (1 << 0), /* Contenu brut attendu */
+ KAP_BIT_FIELD_TYPE = (1 << 1), /* Champ d'un ou plusieurs bits*/
+ KAP_BASIC_TYPE = (1 << 2), /* Type prédéfini */
+ KAP_USER_TYPE = (1 << 3), /* Type personnalisé */
+ KAP_DYNAMIC_TYPE = (1 << 4), /* Type dynmatique */
+ KAP_SIZED = (1 << 5), /* Bourrage dimensionné */
+ KAP_SIZED_EOS = (1 << 6), /* Bourrage final */
+
+} KaitaiAttributePayload;
+
+/* Types de base reconnus par Kaitai */ /* TODO : REMME ? (car non utilisé) */
+typedef enum _KaitaiBasicType
+{
+ KBT_U1, /* Octet non signé */
+ KBT_U2, /* Mot de 16 bits non signé */
+ KBT_U2LE, /* Mot de 16 bits non signé */
+ KBT_U2BE, /* Mot de 16 bits non signé */
+ KBT_U4, /* Mot de 32 bits non signé */
+ KBT_U4LE, /* Mot de 32 bits non signé */
+ KBT_U4BE, /* Mot de 32 bits non signé */
+ KBT_U8, /* Mot de 64 bits non signé */
+ KBT_U8LE, /* Mot de 64 bits non signé */
+ KBT_U8BE, /* Mot de 64 bits non signé */
+ KBT_S1, /* Octet signé */
+ KBT_S2, /* Mot de 16 bits signé */
+ KBT_S2LE, /* Mot de 16 bits signé */
+ KBT_S2BE, /* Mot de 16 bits signé */
+ KBT_S4, /* Mot de 32 bits signé */
+ KBT_S4LE, /* Mot de 32 bits signé */
+ KBT_S4BE, /* Mot de 32 bits signé */
+ KBT_S8, /* Mot de 64 bits signé */
+ KBT_S8LE, /* Mot de 64 bits signé */
+ KBT_S8BE, /* Mot de 64 bits signé */
+ KBT_F4, /* Flottant sur 32 bits */
+ KBT_F4BE, /* Flottant sur 32 bits */
+ KBT_F4LE, /* Flottant sur 32 bits */
+ KBT_F8, /* Flottant sur 64 bits */
+ KBT_F8BE, /* Flottant sur 64 bits */
+ KBT_F8LE, /* Flottant sur 64 bits */
+ KBT_STR, /* Chaîne de caractères */
+ KBT_STRZ, /* Chaîne de caractères + '\0' */
+
+} KaitaiBasicType;
+
+/* Formes de répétition d'une lecture d'attribut */
+typedef enum _KaitaiAttributeRepetition
+{
+ KAR_NO_REPETITION, /* Aucune forme de répétition */
+
+ KAR_END_OF_STREAM, /* Redites autant que possible */
+ KAR_EXPRESSION, /* Répétitions selon quantité */
+ KAR_UNTIL, /* Répétitions sous condition */
+
+} KaitaiAttributeRepetition;
+
+
+/* Indique le type défini pour un attribut de la spécification Kaitai. */
+GType g_kaitai_attribute_get_type(void);
+
+/* Construit un lecteur d'attribut Kaitai. */
+GKaitaiAttribute *g_kaitai_attribute_new(GYamlNode *);
+
+/* Dérive un lecteur d'attribut Kaitai pour un type utilisateur. */
+GKaitaiAttribute *g_kaitai_attribute_dup_for_user_type(const GKaitaiAttribute *, const char *);
+
+/* Indique l'étiquette à utiliser pour identifier un attribut. */
+const char *g_kaitai_attribute_get_label(const GKaitaiAttribute *);
+
+/* Indique la désignation brute d'un identifiant Kaitai. */
+const char *g_kaitai_attribute_get_raw_id(const GKaitaiAttribute *);
+
+/* Indique la désignation originelle d'un identifiant Kaitai. */
+const char *g_kaitai_attribute_get_original_id(const GKaitaiAttribute *);
+
+/* Fournit une éventuelle documentation concernant l'attribut. */
+const char *g_kaitai_attribute_get_doc(const GKaitaiAttribute *);
+
+/* Indique la nature de la charge représentée par l'attribut. */
+KaitaiAttributePayload g_kaitai_attribute_get_payload(const GKaitaiAttribute *);
+
+/* Précise un éventuel type de base reconnu par le lecteur. */
+bool g_kaitai_attribute_get_basic_type(const GKaitaiAttribute *, BaseType *, bool *);
+
+/* Lit les octets d'une chaîne représentée. */
+bool g_kaitai_attribute_read_truncated_bytes(const GKaitaiAttribute *, const GBinContent *, const mrange_t *, bin_t **, size_t *);
+
+/* Détermine si l'attribue porte une valeur entière signée. */
+bool g_kaitai_attribute_handle_signed_integer(const GKaitaiAttribute *);
+
+/* Lit la valeur d'un élément Kaitai entier représenté. */
+bool g_kaitai_attribute_read_value(const GKaitaiAttribute *, const GBinContent *, const mrange_t *, SourceEndian, resolved_value_t *);
+
+/* Lit la valeur d'un champ de bits Kaitai représenté. */
+bool g_kaitai_attribute_read_bit_field_value(const GKaitaiAttribute *, const GBinContent *, const ext_vmpa_t *, uint8_t, SourceEndian, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_ATTRIBUTE_H */
diff --git a/plugins/kaitai/parsers/enum-int.h b/plugins/kaitai/parsers/enum-int.h
new file mode 100644
index 0000000..b62ae41
--- /dev/null
+++ b/plugins/kaitai/parsers/enum-int.h
@@ -0,0 +1,79 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum-int.h - prototypes internes pour la gestion des énumérations Kaitai
+ *
+ * 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_KAITAI_PARSERS_ENUM_INT_H
+#define PLUGINS_KAITAI_PARSERS_ENUM_INT_H
+
+
+#include "enum.h"
+
+
+
+/* ------------------------- MANIPULATION D'UNE ENUMERATION ------------------------- */
+
+
+/* Mémorisation d'une valeur d'énumération */
+typedef struct _enum_value_t
+{
+ resolved_value_t value; /* Valeur entière représentée */
+ char *label; /* Elément associé à une valeur*/
+ char *doc; /* Eventuelle documentation */
+
+} enum_value_t;
+
+
+
+/* ----------------------- GESTION D'UN GROUPE D'ENUMERATIONS ----------------------- */
+
+
+/* Définition d'un ensemble d'énumérations Kaitai (instance) */
+struct _GKaitaiEnum
+{
+ GObject parent; /* A laisser en premier */
+
+ char *name; /* Désignation de l'énumération*/
+
+ enum_value_t **cases_v2l; /* Choix indexés par valeur */
+ size_t cases_v2l_count; /* Quantité de ces choix */
+
+ enum_value_t **cases_l2v; /* Choix indexés par étiquette */
+ size_t cases_l2v_count; /* Quantité de ces choix */
+
+ enum_value_t *defcase; /* Choix par défaut ou NULL */
+
+};
+
+/* Définition d'un ensemble d'énumérations Kaitai (classe) */
+struct _GKaitaiEnumClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un groupe d'énumérations Kaitai. */
+bool g_kaitai_enum_create(GKaitaiEnum *, GYamlNode *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_ENUM_INT_H */
diff --git a/plugins/kaitai/parsers/enum.c b/plugins/kaitai/parsers/enum.c
new file mode 100644
index 0000000..27e5660
--- /dev/null
+++ b/plugins/kaitai/parsers/enum.c
@@ -0,0 +1,765 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum.h - gestion des énumérations Kaitai
+ *
+ * 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 "enum.h"
+
+
+#include <malloc.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include <common/extstr.h>
+#include <common/sort.h>
+#include <core/logs.h>
+#include <plugins/yaml/collection.h>
+#include <plugins/yaml/pair.h>
+
+
+#include "enum-int.h"
+
+
+
+/* ------------------------- MANIPULATION D'UNE ENUMERATION ------------------------- */
+
+
+/* Construit une valeur d'énumération à partir d'indications. */
+static enum_value_t *build_enum_value(GYamlNode *, bool *);
+
+/* Supprime de la mémoire une valeur d'énumération. */
+static void delete_enum_value(enum_value_t *);
+
+/* Etablit la comparaison entre deux valeurs d'énumération. */
+static int compare_enum_values_by_value(const enum_value_t **, const enum_value_t **);
+
+/* Etablit la comparaison entre deux noms d'énumération. */
+static int compare_enum_values_by_label(const enum_value_t **, const enum_value_t **);
+
+/* Etablit la comparaison entre deux noms d'énumération. */
+static int compare_enum_values_by_sized_label(const sized_string_t *, const enum_value_t **);
+
+
+
+/* ----------------------- GESTION D'UN GROUPE D'ENUMERATIONS ----------------------- */
+
+
+/* Initialise la classe des groupes d'énumérations Kaitai. */
+static void g_kaitai_enum_class_init(GKaitaiEnumClass *);
+
+/* Initialise un groupe d'énumérations Kaitai. */
+static void g_kaitai_enum_init(GKaitaiEnum *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_enum_dispose(GKaitaiEnum *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_enum_finalize(GKaitaiEnum *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* MANIPULATION D'UNE ENUMERATION */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud Yaml à venir lire. *
+* defcase = indique si une valeur par défaut est visée. [OUT] *
+* *
+* Description : Construit une valeur d'énumération à partir d'indications. *
+* *
+* Retour : Structure de valeur mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static enum_value_t *build_enum_value(GYamlNode *node, bool *defcase)
+{
+ enum_value_t *result; /* Valeur à retourner */
+ const char *key; /* Clef d'une énumération */
+ kaitai_scope_t fake; /* Contexte de circonstance */
+ resolved_value_t kval; /* Valeur à indexer */
+ const char *value; /* Valeur Yaml particulière */
+ char *path; /* Chemin d'accès suivant */
+ GYamlNode *children; /* Sous-noeuds rattachés */
+ GYamlNode *sub; /* Sous-noeud à considérer */
+
+ result = NULL;
+
+ *defcase = false;
+
+ if (!G_IS_YAML_PAIR(node))
+ goto bad_node;
+
+ /* Identification de la valeur énumérative */
+
+ key = g_yaml_pair_get_key(G_YAML_PAIR(node));
+
+ if (strcmp(key, "_") == 0)
+ {
+ /**
+ * Exemple de choix par défaut :
+ * http://doc.kaitai.io/user_guide.html#tlv
+ */
+
+ kval.type = GVT_UNSIGNED_INTEGER;
+ kval.unsigned_integer = ~0llu;
+
+ *defcase = true;
+
+ }
+
+ else
+ {
+ fake.meta = NULL;
+ fake.root = NULL;
+ fake.parent = NULL;
+ fake.last = NULL;
+
+ if (!resolve_kaitai_expression_as_integer(&fake, key, strlen(key), &kval))
+ goto bad_node;
+
+ }
+
+ /* Récupération des éléments associés à la valeur */
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ {
+ result = malloc(sizeof(enum_value_t));
+
+ result->value = kval;
+ result->label = strdup(value);
+ result->doc = NULL;
+
+ }
+ else
+ {
+ /**
+ * Les énumérations peuvent comporter un commentaire associé
+ * sous forme d'un élément de documentation complémentaire.
+ *
+ * Cf. http://doc.kaitai.io/user_guide.html#verbose-enums
+ */
+
+ asprintf(&path, "/%s/", key);
+ children = g_yaml_node_find_first_by_path(node, path);
+ free(path);
+
+ if (!G_IS_YAML_COLLEC(children))
+ goto bad_value;
+
+ /* Identifiant */
+
+ sub = g_yaml_node_find_first_by_path(children, "/id");
+
+ if (!G_IS_YAML_PAIR(sub))
+ goto bad_sub_value;
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(sub));
+
+ if (value == NULL)
+ goto bad_sub_value;
+
+ result = malloc(sizeof(enum_value_t));
+
+ result->value = kval;
+ result->label = strdup(value);
+ result->doc = NULL;
+
+ g_object_unref(G_OBJECT(sub));
+
+ /* Documentation */
+
+ sub = g_yaml_node_find_first_by_path(children, "/doc");
+
+ if (!G_IS_YAML_PAIR(sub))
+ goto bad_sub_value;
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(sub));
+
+ if (value == NULL)
+ goto bad_sub_value;
+
+ result->doc = strdup(value);
+
+ bad_sub_value:
+
+ g_clear_object(&sub);
+
+ g_object_unref(G_OBJECT(children));
+
+ bad_value:
+
+ ;
+
+ }
+
+ bad_node:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : value = valeur à traiter. *
+* *
+* Description : Supprime de la mémoire une valeur d'énumération. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void delete_enum_value(enum_value_t *value)
+{
+ EXIT_RESOLVED_VALUE(value->value);
+
+ free(value->label);
+
+ if (value->doc != NULL)
+ free(value->doc);
+
+ free(value);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premières informations à consulter. *
+* b = secondes informations à consulter. *
+* *
+* Description : Etablit la comparaison entre deux valeurs d'énumération. *
+* *
+* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_enum_values_by_value(const enum_value_t **a, const enum_value_t **b)
+{
+ int result; /* Bilan à retourner */
+ const resolved_value_t *value_a; /* Raccouri d'accès pour a */
+ const resolved_value_t *value_b; /* Raccouri d'accès pour b */
+
+ value_a = &(*a)->value;
+ value_b = &(*b)->value;
+
+ if (value_a->type == GVT_UNSIGNED_INTEGER && value_b->type == GVT_UNSIGNED_INTEGER)
+ result = sort_unsigned_long_long(value_a->unsigned_integer, value_b->unsigned_integer);
+
+ else if (value_a->type == GVT_UNSIGNED_INTEGER && value_b->type == GVT_UNSIGNED_INTEGER)
+ result = sort_signed_long_long(value_a->signed_integer, value_b->signed_integer);
+
+ else
+ {
+ /**
+ * Le code Python a deux options : soit fournir un équivalent à la
+ * structure resolved_value_t lors de l'appel correspondant à cette
+ * fonction compare_enum_values_by_value(), soit fournir un nombre
+ * directement.
+ *
+ * Comme PyArg_ParseTuple() est obligée de trancher entre non-signé
+ * et signé, le parti est pris de considérer le non-signé coté Python.
+ * On s'adapte en conséquence ici.
+ *
+ * La structure resolved_value_t est une union, donc les valeurs
+ * sont potientiellement au mauvais format mais bien présentes.
+ */
+
+ /**
+ * result = sort_unsigned_long_long(value_a->type, value_b->type);
+ */
+
+ result = sort_unsigned_long_long(value_a->unsigned_integer, value_b->unsigned_integer);
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : a = premières informations à consulter. *
+* b = secondes informations à consulter. *
+* *
+* Description : Etablit la comparaison entre deux noms d'énumération. *
+* *
+* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_enum_values_by_label(const enum_value_t **a, const enum_value_t **b)
+{
+ int result; /* Bilan à retourner */
+
+ result = strcmp((*a)->label, (*b)->label);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : l = premières informations à consulter. *
+* b = secondes informations à consulter. *
+* *
+* Description : Etablit la comparaison entre deux noms d'énumération. *
+* *
+* Retour : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b). *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static int compare_enum_values_by_sized_label(const sized_string_t *l, const enum_value_t **b)
+{
+ int result; /* Bilan à retourner */
+
+ result = strncmp(l->data, (*b)->label, l->len); // FIXME
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* GESTION D'UN GROUPE D'ENUMERATIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un ensemble d'énumérations Kaitai. */
+G_DEFINE_TYPE(GKaitaiEnum, g_kaitai_enum, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des groupes d'énumérations Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_class_init(GKaitaiEnumClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_enum_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_enum_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = instance à initialiser. *
+* *
+* Description : Initialise un groupe d'énumérations Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_init(GKaitaiEnum *kenum)
+{
+ kenum->name = NULL;
+
+ kenum->cases_v2l = NULL;
+ kenum->cases_v2l_count = 0;
+
+ kenum->cases_l2v = NULL;
+ kenum->cases_l2v_count = 0;
+
+ kenum->defcase = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_dispose(GKaitaiEnum *kenum)
+{
+ G_OBJECT_CLASS(g_kaitai_enum_parent_class)->dispose(G_OBJECT(kenum));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_enum_finalize(GKaitaiEnum *kenum)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (kenum->name != NULL)
+ free(kenum->name);
+
+ for (i = 0; i < kenum->cases_v2l_count; i++)
+ delete_enum_value(kenum->cases_v2l[i]);
+
+ if (kenum->cases_v2l != NULL)
+ free(kenum->cases_v2l);
+
+ if (kenum->cases_l2v != NULL)
+ free(kenum->cases_l2v);
+
+ if (kenum->defcase != NULL)
+ delete_enum_value(kenum->defcase);
+
+ G_OBJECT_CLASS(g_kaitai_enum_parent_class)->finalize(G_OBJECT(kenum));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Construit un groupe d'énumérations Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiEnum *g_kaitai_enum_new(GYamlNode *parent)
+{
+ GKaitaiEnum *result; /* Identifiant à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_ENUM, NULL);
+
+ if (!g_kaitai_enum_create(result, parent))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Met en place un groupe d'énumérations Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_enum_create(GKaitaiEnum *kenum, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ char *path; /* Chemin des valeurs */
+ GYamlNode *collec; /* Liste de noeuds à traiter */
+ GYamlNode **nodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+ bool defcase; /* Définition par défaut ? */
+ enum_value_t *value; /* Valeur énumérative nouvelle */
+ bool found; /* Présence de partage existant*/
+ size_t index; /* Indice du point d'insertion */
+
+ result = false;
+
+ /* Récupération du nom */
+
+ if (!G_IS_YAML_PAIR(parent)) goto exit;
+
+ kenum->name = strdup(g_yaml_pair_get_key(G_YAML_PAIR(parent)));
+
+ /* Association de valeurs */
+
+ path = strdup("/");
+ path = stradd(path, kenum->name);
+ path = stradd(path, "/");
+
+ collec = g_yaml_node_find_first_by_path(parent, path);
+
+ free(path);
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ for (i = 0; i < count; i++)
+ {
+ value = build_enum_value(nodes[i], &defcase);
+ if (value == NULL) break;
+
+ if (defcase)
+ {
+ if (kenum->defcase != NULL)
+ {
+ log_variadic_message(LMT_WARNING,
+ _("Multiple definition of the defaut value for the enumeration '%s'"),
+ kenum->name);
+
+ delete_enum_value(value);
+ break;
+
+ }
+
+ /**
+ * Exemple de choix par défaut :
+ * http://doc.kaitai.io/user_guide.html#tlv
+ */
+
+ kenum->defcase = value;
+
+ }
+
+ else
+ {
+ kenum->cases_v2l = qinsert(kenum->cases_v2l, &kenum->cases_v2l_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_value, &value);
+
+ found = bsearch_index(&value, kenum->cases_l2v, kenum->cases_l2v_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_label, &index);
+
+ if (found)
+ log_variadic_message(LMT_WARNING,
+ _("Multiple occurrence of the label %s in the enumeration '%s'"),
+ value->label, kenum->name);
+
+ else
+ kenum->cases_l2v = _qinsert(kenum->cases_l2v, &kenum->cases_l2v_count, sizeof(enum_value_t *),
+ &value, index);
+
+ }
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
+
+ result = (i == count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ free(nodes);
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* *
+* Description : Fournit le nom principal d'une énumération. *
+* *
+* Retour : Désignation de l'énumération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_enum_get_name(const GKaitaiEnum *kenum)
+{
+ const char *result; /* Chaîne à retourner */
+
+ result = kenum->name;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* label = étiquette de l'élément constant à traduire. *
+* value = valeur concrète correspondante. [OUT] *
+* *
+* Description : Traduit une étiquette brute en constante d'énumération. *
+* *
+* Retour : Bilan de la conversion. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_enum_find_value(const GKaitaiEnum *kenum, const sized_string_t *label, resolved_value_t *value)
+{
+ bool result; /* Présence à retourner */
+ size_t index; /* Indice du point d'insertion */
+
+ result = bsearch_index(label, kenum->cases_l2v, kenum->cases_l2v_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_sized_label, &index);
+
+ if (result)
+ *value = kenum->cases_l2v[index]->value;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* value = valeur concrète à transformer. *
+* prefix = détermine l'ajout d'un préfixe éventuel. *
+* *
+* Description : Traduit une constante d'énumération en étiquette brute. *
+* *
+* Retour : Désignation ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_kaitai_enum_find_label(const GKaitaiEnum *kenum, const resolved_value_t *value, bool prefix)
+{
+ char *result; /* Etiquette à retourner */
+ enum_value_t faked; /* Copie d'élément recherché */
+ bool found; /* Présence de partage existant*/
+ size_t index; /* Indice du point d'insertion */
+ const enum_value_t *item; /* Elément retrouvé par valeur */
+
+ faked.value = *value;
+
+ found = bsearch_index(&faked, kenum->cases_v2l, kenum->cases_v2l_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_value, &index);
+
+ if (found)
+ item = kenum->cases_l2v[index];
+ else
+ item = kenum->defcase;
+
+ if (item != NULL)
+ {
+ if (prefix)
+ asprintf(&result, "%s::%s", kenum->name, item->label);
+ else
+ result = strdup(item->label);
+ }
+
+ else
+ result = NULL;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kenum = groupe d'énumérations à consulter. *
+* value = valeur concrète à transformer. *
+* *
+* Description : Traduit une constante d'énumération en documentation. *
+* *
+* Retour : Documentation associée à la valeur indiquée ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+char *g_kaitai_enum_find_documentation(const GKaitaiEnum *kenum, const resolved_value_t *value)
+{
+ char *result; /* Documentation à retourner */
+ enum_value_t faked; /* Copie d'élément recherché */
+ bool found; /* Présence de partage existant*/
+ size_t index; /* Indice du point d'insertion */
+ const enum_value_t *item; /* Elément retrouvé par valeur */
+
+ faked.value = *value;
+
+ found = bsearch_index(&faked, kenum->cases_v2l, kenum->cases_v2l_count, sizeof(enum_value_t *),
+ (__compar_fn_t)compare_enum_values_by_value, &index);
+
+ if (found)
+ item = kenum->cases_l2v[index];
+ else
+ item = kenum->defcase;
+
+ if (item != NULL)
+ result = strdup(item->doc);
+ else
+ result = NULL;
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/enum.h b/plugins/kaitai/parsers/enum.h
new file mode 100644
index 0000000..9e4bf2a
--- /dev/null
+++ b/plugins/kaitai/parsers/enum.h
@@ -0,0 +1,76 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * enum.h - prototypes pour la gestion des énumérations Kaitai
+ *
+ * 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_KAITAI_PARSERS_ENUM_H
+#define _PLUGINS_KAITAI_PARSERS_ENUM_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+#include <stdint.h>
+
+
+#include <common/szstr.h>
+#include <plugins/yaml/node.h>
+
+
+#include "../expression.h"
+
+
+
+#define G_TYPE_KAITAI_ENUM g_kaitai_enum_get_type()
+#define G_KAITAI_ENUM(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_ENUM, GKaitaiEnum))
+#define G_IS_KAITAI_ENUM(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_ENUM))
+#define G_KAITAI_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_ENUM, GKaitaiEnumClass))
+#define G_IS_KAITAI_ENUM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_ENUM))
+#define G_KAITAI_ENUM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_ENUM, GKaitaiEnumClass))
+
+
+/* Définition d'un ensemble d'énumérations Kaitai (instance) */
+typedef struct _GKaitaiEnum GKaitaiEnum;
+
+/* Définition d'un ensemble d'énumérations Kaitai (classe) */
+typedef struct _GKaitaiEnumClass GKaitaiEnumClass;
+
+
+/* Indique le type défini pour un ensemble d'énumérations Kaitai. */
+GType g_kaitai_enum_get_type(void);
+
+/* Construit un groupe d'énumérations Kaitai. */
+GKaitaiEnum *g_kaitai_enum_new(GYamlNode *);
+
+/* Fournit le nom principal d'une énumération. */
+const char *g_kaitai_enum_get_name(const GKaitaiEnum *);
+
+/* Traduit une étiquette brute en constante d'énumération. */
+bool g_kaitai_enum_find_value(const GKaitaiEnum *, const sized_string_t *, resolved_value_t *);
+
+/* Traduit une constante d'énumération en étiquette brute. */
+char *g_kaitai_enum_find_label(const GKaitaiEnum *, const resolved_value_t *, bool);
+
+/* Traduit une constante d'énumération en documentation. */
+char *g_kaitai_enum_find_documentation(const GKaitaiEnum *, const resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_ENUM_H */
diff --git a/plugins/kaitai/parsers/instance-int.h b/plugins/kaitai/parsers/instance-int.h
new file mode 100644
index 0000000..6f098b4
--- /dev/null
+++ b/plugins/kaitai/parsers/instance-int.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance-int.h - prototypes pour les spécifications internes d'une instance Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H
+#define _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H
+
+
+#include "attribute-int.h"
+#include "instance.h"
+
+
+
+/* Spécification d'une instance Kaitai (instance) */
+struct _GKaitaiInstance
+{
+ GKaitaiAttribute parent; /* A laisser en premier */
+
+ char *name; /* Nom attribué à l'instance */
+
+ char *io; /* Contenu binaire forcé */
+ char *pos; /* Position forcée */
+ char *value; /* Formule pour calcul */
+
+};
+
+/* Spécification d'une instance Kaitai (classe) */
+struct _GKaitaiInstanceClass
+{
+ GKaitaiAttributeClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un lecteur d'instance Kaitai. */
+bool g_kaitai_instance_create(GKaitaiInstance *, GYamlNode *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_INSTANCE_INT_H */
diff --git a/plugins/kaitai/parsers/instance.c b/plugins/kaitai/parsers/instance.c
new file mode 100644
index 0000000..d62c1f6
--- /dev/null
+++ b/plugins/kaitai/parsers/instance.c
@@ -0,0 +1,503 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance.c - spécification d'une instance Kaitai
+ *
+ * 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 "instance.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include <plugins/yaml/pair.h>
+
+
+#include "instance-int.h"
+#include "../expression.h"
+#include "../records/delayed.h"
+
+
+
+/* -------------------- CORRESPONDANCE ENTRE INSTANCE ET BINAIRE -------------------- */
+
+
+/* Initialise la classe des instances de spécification Kaitai. */
+static void g_kaitai_instance_class_init(GKaitaiInstanceClass *);
+
+/* Initialise une instance de spécification Kaitai. */
+static void g_kaitai_instance_init(GKaitaiInstance *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_instance_dispose(GKaitaiInstance *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_instance_finalize(GKaitaiInstance *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_instance_parse_content(GKaitaiInstance *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* CORRESPONDANCE ENTRE INSTANCE ET BINAIRE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une instance de la spécification Kaitai. */
+G_DEFINE_TYPE(GKaitaiInstance, g_kaitai_instance, G_TYPE_KAITAI_ATTRIBUTE);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des instances de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_class_init(GKaitaiInstanceClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Ancêtre parent de la classe */
+ GKaitaiAttributeClass *attrib; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_instance_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_instance_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_instance_parse_content;
+
+ attrib = G_KAITAI_ATTRIBUTE_CLASS(klass);
+
+ attrib->get_label = (get_attribute_label_fc)g_kaitai_instance_get_name;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = instance à initialiser. *
+* *
+* Description : Initialise une instance de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_init(GKaitaiInstance *inst)
+{
+ inst->name = NULL;
+
+ inst->io = NULL;
+ inst->pos = NULL;
+ inst->value = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_dispose(GKaitaiInstance *inst)
+{
+ G_OBJECT_CLASS(g_kaitai_instance_parent_class)->dispose(G_OBJECT(inst));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_instance_finalize(GKaitaiInstance *inst)
+{
+ if (inst->name != NULL)
+ free(inst->name);
+
+ if (inst->io != NULL)
+ free(inst->io);
+
+ if (inst->pos != NULL)
+ free(inst->pos);
+
+ if (inst->value != NULL)
+ free(inst->value);
+
+ G_OBJECT_CLASS(g_kaitai_instance_parent_class)->finalize(G_OBJECT(inst));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'instance à constituer. *
+* *
+* Description : Construit un lecteur d'instance Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiInstance *g_kaitai_instance_new(GYamlNode *parent)
+{
+ GKaitaiInstance *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_INSTANCE, NULL);
+
+ if (!g_kaitai_instance_create(result, parent))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à initialiser pleinement. *
+* parent = noeud Yaml contenant l'instance à constituer. *
+* *
+* Description : Met en place un lecteur d'instance Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_instance_create(GKaitaiInstance *inst, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ const char *name; /* Désignation du type */
+ char *sub_path; /* Chemin d'accès suivant */
+ GYamlNode *sub; /* Contenu Yaml d'un type */
+ GYamlNode *node; /* Noeud particulier présent */
+ const char *value; /* Valeur Yaml particulière */
+
+ result = false;
+
+ /* Extraction du nom */
+
+ if (!G_IS_YAML_PAIR(parent))
+ goto exit;
+
+ name = g_yaml_pair_get_key(G_YAML_PAIR(parent));
+
+ inst->name = strdup(name);
+
+ /* Extraction des bases du type */
+
+ asprintf(&sub_path, "/%s/", name);
+ sub = g_yaml_node_find_first_by_path(parent, sub_path);
+ free(sub_path);
+
+ if (sub == NULL)
+ goto exit;
+
+ result = g_kaitai_attribute_create(G_KAITAI_ATTRIBUTE(inst), sub, false);
+
+ /* Eventuel contenu imposé */
+
+ node = g_yaml_node_find_first_by_path(sub, "/io");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_loading;
+ }
+
+ inst->io = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Eventuelle positiion imposée */
+
+ node = g_yaml_node_find_first_by_path(sub, "/pos");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(node));
+ goto bad_loading;
+ }
+
+ inst->pos = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Eventuelle formule de calcul d'une valeur */
+
+ node = g_yaml_node_find_first_by_path(sub, "/value");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ inst->value = g_yaml_pair_aggregate_value(G_YAML_PAIR(node));
+
+ g_object_unref(G_OBJECT(node));
+
+ if (inst->value == NULL)
+ goto bad_loading;
+
+ }
+
+ bad_loading:
+
+ g_object_unref(G_OBJECT(sub));
+
+ exit:
+
+ if (result)
+ result = (inst->pos != NULL || inst->value != NULL);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à consulter. *
+* *
+* Description : Indique le nom attribué à une instance Kaitai. *
+* *
+* Retour : Désignation pointant l'instance. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_instance_get_name(const GKaitaiInstance *inst)
+{
+ char *result; /* Valeur à renvoyer */
+
+ result = inst->name;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à consulter. *
+* locals = variables locales pour les résolutions de types. *
+* content = contenu binaire lié à la correspondance. *
+* *
+* Description : Détermine la valeur effective d'un élément Kaitai dynamique. *
+* *
+* Retour : valeur à sauvegarder sous une forme générique. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *g_kaitai_instance_compute_real_record(const GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content)
+{
+ GMatchRecord *result; /* Enregistrement à retourner */
+ GBinContent *work_area; /* Aire de travail */
+ GKaitaiStream *stream; /* Flux de données pour Kaitai */
+ bool status; /* Bilan intermédiaire */
+ vmpa2t forced_pos; /* Tete de lecture constituée */
+ resolved_value_t offset; /* Position à adopter */
+ GKaitaiParserClass *class; /* Classe parente à solliciter */
+ ext_vmpa_t epos; /* Tête de lecture complète */
+
+ result = NULL;
+
+ if (inst->value == NULL)
+ {
+ /* Contenu particulier */
+
+ if (inst->io == NULL)
+ work_area = content;
+
+ else
+ {
+ status = resolve_kaitai_expression_as_stream(locals, inst->io, strlen(inst->io), &stream);
+ if (!status) goto exit;
+
+ work_area = g_kaitai_stream_get_content(stream);
+
+ g_object_unref(G_OBJECT(stream));
+
+ }
+
+ /* Tête de lecture */
+
+ g_binary_content_compute_start_pos(work_area, &forced_pos);
+
+ status = resolve_kaitai_expression_as_integer(locals, inst->pos, strlen(inst->pos), &offset);
+ if (!status) goto exit_with_content;
+
+ if (offset.type == GVT_UNSIGNED_INTEGER)
+ advance_vmpa(&forced_pos, offset.unsigned_integer);
+
+ else
+ {
+ assert(offset.type == GVT_SIGNED_INTEGER);
+
+ if (offset.signed_integer < 0)
+ {
+ status = false;
+ goto exit_with_content;
+ }
+
+ advance_vmpa(&forced_pos, offset.signed_integer);
+
+ }
+
+ /* Lecture */
+
+ class = G_KAITAI_PARSER_CLASS(g_kaitai_instance_parent_class);
+
+ init_evmpa_from_vmpa(&epos, &forced_pos);
+
+ class->parse(G_KAITAI_PARSER(inst), locals, work_area, &epos, &result);
+
+ exit_with_content:
+
+ if (work_area != content)
+ g_object_unref(G_OBJECT(work_area));
+
+ }
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = lecteur d'instance Kaitai à consulter. *
+* locals = variables locales pour les résolutions de types. *
+* value = valeur à sauvegarder sous une forme générique. [OUT]*
+* *
+* Description : Détermine la valeur d'un élément Kaitai entier calculé. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_instance_compute_value(const GKaitaiInstance *inst, const kaitai_scope_t *locals, resolved_value_t *value)
+{
+ bool result; /* Bilan à retourner */
+
+ if (inst->value == NULL)
+ result = false;
+
+ else
+ result = resolve_kaitai_expression_as_any(locals,
+ inst->value,
+ strlen(inst->value),
+ value);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : inst = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+
+ *record = G_MATCH_RECORD(g_record_delayed_new(inst, locals, inst->value == NULL ? content : NULL));
+
+ result = (*record != NULL);
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/instance.h b/plugins/kaitai/parsers/instance.h
new file mode 100644
index 0000000..4594137
--- /dev/null
+++ b/plugins/kaitai/parsers/instance.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * instance.h - prototypes pour la spécification d'une instance Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_INSTANCE_H
+#define _PLUGINS_KAITAI_PARSERS_INSTANCE_H
+
+
+#include <glib-object.h>
+
+
+#include <plugins/yaml/node.h>
+
+
+#include "../expression.h"
+#include "../scope.h"
+
+
+
+#define G_TYPE_KAITAI_INSTANCE g_kaitai_instance_get_type()
+#define G_KAITAI_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_INSTANCE, GKaitaiInstance))
+#define G_IS_KAITAI_INSTANCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_INSTANCE))
+#define G_KAITAI_INSTANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_INSTANCE, GKaitaiInstanceClass))
+#define G_IS_KAITAI_INSTANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_INSTANCE))
+#define G_KAITAI_INSTANCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_INSTANCE, GKaitaiInstanceClass))
+
+
+/* Spécification d'une instance Kaitai (instance) */
+typedef struct _GKaitaiInstance GKaitaiInstance;
+
+/* Spécification d'une instance Kaitai (classe) */
+typedef struct _GKaitaiInstanceClass GKaitaiInstanceClass;
+
+
+/* Indique le type défini pour une instance de la spécification Kaitai. */
+GType g_kaitai_instance_get_type(void);
+
+/* Construit un lecteur d'instance Kaitai. */
+GKaitaiInstance *g_kaitai_instance_new(GYamlNode *);
+
+/* Indique le nom attribué à une instance Kaitai. */
+const char *g_kaitai_instance_get_name(const GKaitaiInstance *);
+
+/* Détermine la valeur effective d'un élément Kaitai dynamique. */
+GMatchRecord *g_kaitai_instance_compute_real_record(const GKaitaiInstance *, const kaitai_scope_t *, GBinContent *);
+
+/* Détermine la valeur d'un élément Kaitai entier calculé. */
+bool g_kaitai_instance_compute_value(const GKaitaiInstance *, const kaitai_scope_t *, resolved_value_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_INSTANCE_H */
diff --git a/plugins/kaitai/parsers/meta-int.h b/plugins/kaitai/parsers/meta-int.h
new file mode 100644
index 0000000..5fe9174
--- /dev/null
+++ b/plugins/kaitai/parsers/meta-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * meta-int.h - prototypes internes pour la description globale d'une définition Kaitai
+ *
+ * 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_KAITAI_PARSERS_META_INT_H
+#define PLUGINS_KAITAI_PARSERS_META_INT_H
+
+
+#include "meta.h"
+
+
+
+/* Description globale d'une définition Kaitai (instance) */
+struct _GKaitaiMeta
+{
+ GObject parent; /* A laisser en premier */
+
+ char *id; /* Identifiant attribué */
+ char *title; /* Désignation de la définition*/
+
+ SourceEndian endian; /* Boutisme par défaut */
+
+ char **dependencies; /* Définitions à importer */
+ size_t dep_count; /* Nombre de ces définitions */
+
+};
+
+/* Description globale d'une définition Kaitai (classe) */
+struct _GKaitaiMetaClass
+{
+ GObjectClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une description globale Kaitai. */
+bool g_kaitai_meta_create(GKaitaiMeta *, GYamlNode *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_META_INT_H */
diff --git a/plugins/kaitai/parsers/meta.c b/plugins/kaitai/parsers/meta.c
new file mode 100644
index 0000000..132eefd
--- /dev/null
+++ b/plugins/kaitai/parsers/meta.c
@@ -0,0 +1,398 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * meta.c - description globale d'une définition Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "meta.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+#include <string.h>
+
+
+#include <plugins/yaml/pair.h>
+
+
+#include "meta-int.h"
+
+
+
+/* Initialise la classe des descriptions globales Kaitai. */
+static void g_kaitai_meta_class_init(GKaitaiMetaClass *);
+
+/* Initialise une description globale de définition Kaitai. */
+static void g_kaitai_meta_init(GKaitaiMeta *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_meta_dispose(GKaitaiMeta *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_meta_finalize(GKaitaiMeta *);
+
+
+
+/* Indique le type défini pour une description globale Kaitai. */
+G_DEFINE_TYPE(GKaitaiMeta, g_kaitai_meta, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des descriptions globales Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_meta_class_init(GKaitaiMetaClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_meta_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_meta_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = instance à initialiser. *
+* *
+* Description : Initialise une description globale de définition Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_meta_init(GKaitaiMeta *meta)
+{
+ meta->id = NULL;
+ meta->title = NULL;
+
+ meta->endian = SRE_LITTLE;
+
+ meta->dependencies = NULL;
+ meta->dep_count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_meta_dispose(GKaitaiMeta *meta)
+{
+ G_OBJECT_CLASS(g_kaitai_meta_parent_class)->dispose(G_OBJECT(meta));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_meta_finalize(GKaitaiMeta *meta)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (meta->id != NULL)
+ free(meta->id);
+
+ if (meta->title != NULL)
+ free(meta->title);
+
+ for (i = 0; i < meta->dep_count; i++)
+ free(meta->dependencies[i]);
+
+ if (meta->dependencies != NULL)
+ free(meta->dependencies);
+
+ G_OBJECT_CLASS(g_kaitai_meta_parent_class)->finalize(G_OBJECT(meta));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Construit une description globale Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiMeta *g_kaitai_meta_new(GYamlNode *parent)
+{
+ GKaitaiMeta *result; /* Identifiant à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_META, NULL);
+
+ if (!g_kaitai_meta_create(result, parent))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = description globale à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Met en place une description globale Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_meta_create(GKaitaiMeta *meta, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *node; /* Noeud particulier présent */
+ const char *value; /* Valeur Yaml particulière */
+ GYamlNode **nodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+
+ result = true;
+
+ /* Identifiant */
+
+ node = g_yaml_node_find_first_by_path(parent, "/meta/id");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ meta->id = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Titre */
+
+ node = g_yaml_node_find_first_by_path(parent, "/meta/title");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value != NULL)
+ meta->title = strdup(value);
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Boutisme */
+
+ node = g_yaml_node_find_first_by_path(parent, "/meta/endian");
+
+ if (node != NULL)
+ {
+ assert(G_IS_YAML_PAIR(node));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (strcmp(value, "le") == 0)
+ meta->endian = SRE_LITTLE;
+
+ else if (strcmp(value, "be") == 0)
+ meta->endian = SRE_BIG;
+
+ g_object_unref(G_OBJECT(node));
+
+ }
+
+ /* Imports */
+
+ node = g_yaml_node_find_first_by_path(parent, "/meta/imports/");
+
+ if (node != NULL)
+ {
+ result = G_IS_YAML_COLLEC(node);
+
+ if (result)
+ {
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(node), &count);
+
+ for (i = 0; i < count; i++)
+ {
+ if (!G_IS_YAML_PAIR(nodes[i]))
+ break;
+
+ value = g_yaml_pair_get_key(G_YAML_PAIR(nodes[i]));
+
+ meta->dependencies = realloc(meta->dependencies, ++meta->dep_count * sizeof(char *));
+
+ meta->dependencies[meta->dep_count - 1] = strdup(value);
+
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ }
+
+ result = (i == count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(nodes[i]));
+
+ if (nodes != NULL)
+ free(nodes);
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = description globale à consulter. *
+* *
+* Description : Fournit l'identifié associé à une définiton Kaitai. *
+* *
+* Retour : Identifiant de définition complète ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_meta_get_id(const GKaitaiMeta *meta)
+{
+ const char *result; /* Chaîne à retourner */
+
+ result = meta->id;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = description globale à consulter. *
+* *
+* Description : Fournit la désignation humaine d'une définiton Kaitai. *
+* *
+* Retour : Intitulé de définition ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_meta_get_title(const GKaitaiMeta *meta)
+{
+ const char *result; /* Chaîne à retourner */
+
+ result = meta->title;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = description globale à consulter. *
+* *
+* Description : Indique le boustime observé par défaut par une définiton. *
+* *
+* Retour : Boustime, petit par défaut. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+SourceEndian g_kaitai_meta_get_endian(const GKaitaiMeta *meta)
+{
+ SourceEndian result; /* Chaîne à retourner */
+
+ result = meta->endian;
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : meta = description globale à consulter. *
+* count = quantité de définitions à importer. [OUT] *
+* *
+* Description : Indique la liste des définitions à importer. *
+* *
+* Retour : Liste de désignations de définitions ou NULL. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char * const *g_kaitai_meta_get_dependencies(const GKaitaiMeta *meta, size_t *count)
+{
+ const char * const *result; /* Liste à retourner */
+
+ result = (const char * const *)meta->dependencies;
+
+ *count = meta->dep_count;
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/meta.h b/plugins/kaitai/parsers/meta.h
new file mode 100644
index 0000000..b8b685d
--- /dev/null
+++ b/plugins/kaitai/parsers/meta.h
@@ -0,0 +1,71 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * meta.h - prototypes pour la description globale d'une définition Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_META_H
+#define _PLUGINS_KAITAI_PARSERS_META_H
+
+
+#include <glib-object.h>
+
+
+#include <common/endianness.h>
+#include <plugins/yaml/node.h>
+
+
+
+#define G_TYPE_KAITAI_META g_kaitai_meta_get_type()
+#define G_KAITAI_META(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_META, GKaitaiMeta))
+#define G_IS_KAITAI_META(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_META))
+#define G_KAITAI_META_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_META, GKaitaiMetaClass))
+#define G_IS_KAITAI_META_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_META))
+#define G_KAITAI_META_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_META, GKaitaiMetaClass))
+
+
+/* Description globale d'une définition Kaitai (instance) */
+typedef struct _GKaitaiMeta GKaitaiMeta;
+
+/* Description globale d'une définition Kaitai (classe) */
+typedef struct _GKaitaiMetaClass GKaitaiMetaClass;
+
+
+/* Indique le type défini pour une description globale Kaitai. */
+GType g_kaitai_meta_get_type(void);
+
+/* Construit une description globale Kaitai. */
+GKaitaiMeta *g_kaitai_meta_new(GYamlNode *);
+
+/* Fournit l'identifié associé à une définiton Kaitai. */
+const char *g_kaitai_meta_get_id(const GKaitaiMeta *);
+
+/* Fournit la désignation humaine d'une définiton Kaitai. */
+const char *g_kaitai_meta_get_title(const GKaitaiMeta *);
+
+/* Indique le boustime observé par défaut par une définiton. */
+SourceEndian g_kaitai_meta_get_endian(const GKaitaiMeta *);
+
+/* Indique la liste des définitions à importer. */
+const char * const *g_kaitai_meta_get_dependencies(const GKaitaiMeta *, size_t *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_META_H */
diff --git a/plugins/kaitai/parsers/struct-int.h b/plugins/kaitai/parsers/struct-int.h
new file mode 100644
index 0000000..6eb6e53
--- /dev/null
+++ b/plugins/kaitai/parsers/struct-int.h
@@ -0,0 +1,77 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct-int.h - prototypes internes pour la définition d'une structure Kaitai
+ *
+ * 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_KAITAI_PARSERS_STRUCT_INT_H
+#define PLUGINS_KAITAI_PARSERS_STRUCT_INT_H
+
+
+#include "attribute.h"
+#include "instance.h"
+#include "struct.h"
+#include "../parser-int.h"
+
+
+
+/* Spécification d'une structure Kaitai (instance) */
+struct _GKaitaiStruct
+{
+ GKaitaiParser parent; /* A laisser en premier */
+
+ char *filename; /* Eventuelle source de données*/
+
+ GKaitaiMeta *meta; /* Description globale */
+
+ GKaitaiAttribute **seq_items; /* Sous-attributs présents */
+ size_t seq_items_count; /* Quantité de ces attributs */
+
+ GKaitaiType **types; /* Types particuliers définis */
+ size_t types_count; /* Quantité de ces types */
+
+ GKaitaiInstance **instances; /* Instances prises en charge */
+ size_t instances_count; /* Quantité de ces instances */
+
+ GKaitaiEnum **enums; /* Enumérations locales */
+ size_t enums_count; /* Quantité de ces énumérations*/
+
+};
+
+/* Spécification d'une structure Kaitai (classe) */
+struct _GKaitaiStructClass
+{
+ GKaitaiParserClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un interpréteur de définitions Kaitai. */
+bool g_kaitai_structure_create_from_text(GKaitaiStruct *, const char *);
+
+/* Met en place un interpréteur de définitions Kaitai. */
+bool g_kaitai_structure_create_from_file(GKaitaiStruct *, const char *);
+
+/* Met en place un lecteur de définitions Kaitai. */
+bool g_kaitai_structure_create(GKaitaiStruct *, GYamlNode *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_STRUCT_INT_H */
diff --git a/plugins/kaitai/parsers/struct.c b/plugins/kaitai/parsers/struct.c
new file mode 100644
index 0000000..d447cf3
--- /dev/null
+++ b/plugins/kaitai/parsers/struct.c
@@ -0,0 +1,837 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct.c - définition d'une structure Kaitai
+ *
+ * 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 "struct.h"
+
+
+#include <assert.h>
+#include <string.h>
+
+
+#include <plugins/yaml/collection.h>
+#include <plugins/yaml/parser.h>
+
+
+#include "struct-int.h"
+#include "../import.h"
+#include "../parser.h"
+#include "../records/empty.h"
+#include "../records/group.h"
+
+
+
+/* ---------------------- LECTURE D'UNE TRANCHE DE DEFINITIONS ---------------------- */
+
+
+/* Initialise la classe des structuts de spécification Kaitai. */
+static void g_kaitai_structure_class_init(GKaitaiStructClass *);
+
+/* Initialise un structut de spécification Kaitai. */
+static void g_kaitai_structure_init(GKaitaiStruct *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_structure_dispose(GKaitaiStruct *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_structure_finalize(GKaitaiStruct *);
+
+/* Charge les éventuelles dépendances de la définition. */
+static bool g_kaitai_structure_load_imports(GKaitaiStruct *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_structure_parse_content(GKaitaiStruct *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* LECTURE D'UNE TRANCHE DE DEFINITIONS */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un structut de la spécification Kaitai. */
+G_DEFINE_TYPE(GKaitaiStruct, g_kaitai_structure, G_TYPE_KAITAI_PARSER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des structuts de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_class_init(GKaitaiStructClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_structure_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_structure_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_structure_parse_content;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = instance à initialiser. *
+* *
+* Description : Initialise un structure de spécification Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_init(GKaitaiStruct *kstruct)
+{
+ kstruct->filename = NULL;
+
+ kstruct->meta = NULL;
+
+ kstruct->seq_items = NULL;
+ kstruct->seq_items_count = 0;
+
+ kstruct->types = NULL;
+ kstruct->types_count = 0;
+
+ kstruct->instances = NULL;
+ kstruct->instances_count = 0;
+
+ kstruct->enums = NULL;
+ kstruct->enums_count = 0;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_dispose(GKaitaiStruct *kstruct)
+{
+ size_t i; /* Boucle de parcours */
+
+ g_clear_object(&kstruct->meta);
+
+ for (i = 0; i < kstruct->seq_items_count; i++)
+ g_clear_object(&kstruct->seq_items[i]);
+
+ for (i = 0; i < kstruct->types_count; i++)
+ g_clear_object(&kstruct->types[i]);
+
+ for (i = 0; i < kstruct->instances_count; i++)
+ g_clear_object(&kstruct->instances[i]);
+
+ for (i = 0; i < kstruct->enums_count; i++)
+ g_clear_object(&kstruct->enums[i]);
+
+ G_OBJECT_CLASS(g_kaitai_structure_parent_class)->dispose(G_OBJECT(kstruct));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_structure_finalize(GKaitaiStruct *kstruct)
+{
+ if (kstruct->filename != NULL)
+ free(kstruct->filename);
+
+ if (kstruct->seq_items != NULL)
+ free(kstruct->seq_items);
+
+ if (kstruct->types != NULL)
+ free(kstruct->types);
+
+ if (kstruct->instances != NULL)
+ free(kstruct->instances);
+
+ if (kstruct->enums != NULL)
+ free(kstruct->enums);
+
+ G_OBJECT_CLASS(g_kaitai_structure_parent_class)->finalize(G_OBJECT(kstruct));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : text = définitions textuelles d'un contenu brut. *
+* *
+* Description : Crée un nouvel interpréteur de structure Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiStruct *g_kaitai_structure_new_from_text(const char *text)
+{
+ GKaitaiStruct *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_STRUCT, NULL);
+
+ if (!g_kaitai_structure_create_from_text(result, text))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* text = définitions textuelles d'un contenu brut. *
+* *
+* Description : Met en place un interpréteur de définitions Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_structure_create_from_text(GKaitaiStruct *kstruct, const char *text)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *root; /* Noeud racine YAML */
+
+ root = parse_yaml_from_text(text, strlen(text));
+
+ if (root != NULL)
+ {
+ result = g_kaitai_structure_create(kstruct, root);
+ g_object_unref(G_OBJECT(root));
+ }
+ else
+ {
+ fprintf(stderr, "The provided YAML content seems invalid");
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : filename = chemin vers des définitions de règles. *
+* *
+* Description : Crée un nouvel interpréteur de structure Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiStruct *g_kaitai_structure_new_from_file(const char *filename)
+{
+ GKaitaiStruct *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_STRUCT, NULL);
+
+ if (!g_kaitai_structure_create_from_file(result, filename))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* filename = chemin vers des définitions de règles. *
+* *
+* Description : Met en place un interpréteur de définitions Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_structure_create_from_file(GKaitaiStruct *kstruct, const char *filename)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *root; /* Noeud racine YAML */
+
+ kstruct->filename = strdup(filename);
+
+ root = parse_yaml_from_file(filename);
+
+ if (root != NULL)
+ {
+ result = g_kaitai_structure_create(kstruct, root);
+ g_object_unref(G_OBJECT(root));
+ }
+ else
+ {
+ fprintf(stderr, "The provided YAML content seems invalid");
+ result = false;
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Met en place un lecteur de définitions Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_structure_create(GKaitaiStruct *kstruct, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *collec; /* Liste de noeuds à traiter */
+ GYamlNode **nodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+ size_t first; /* Premier emplacement dispo. */
+ bool failed; /* Détection d'un échec */
+
+ result = false;
+
+ /* Informations générales */
+
+ kstruct->meta = g_kaitai_meta_new(parent);
+ assert(kstruct->meta != NULL);
+
+ result = g_kaitai_structure_load_imports(kstruct);
+ if (!result) goto bad_loading;
+
+ /* Séquence */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/seq/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ kstruct->seq_items = calloc(count, sizeof(GKaitaiAttribute *));
+ kstruct->seq_items_count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->seq_items[i] = g_kaitai_attribute_new(nodes[i]);
+ if (kstruct->seq_items[i] == NULL) 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)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Types particuliers éventuels */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/types/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ first = kstruct->types_count;
+
+ kstruct->types_count += count;
+ kstruct->types = realloc(kstruct->types, kstruct->types_count * sizeof(GKaitaiType *));
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->types[first + i] = g_kaitai_type_new(nodes[i]);
+ if (kstruct->types[first + i] == NULL) 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)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Instances éventuelles */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/instances/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ kstruct->instances = calloc(count, sizeof(GKaitaiInstance *));
+ kstruct->instances_count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->instances[i] = g_kaitai_instance_new(nodes[i]);
+ if (kstruct->instances[i] == NULL) 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)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Enumérations éventuelles */
+
+ collec = g_yaml_node_find_first_by_path(parent, "/enums/");
+
+ if (collec != NULL)
+ {
+ if (G_IS_YAML_COLLEC(collec))
+ nodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+ else
+ count = 0;
+
+ if (count > 0)
+ {
+ kstruct->enums = calloc(count, sizeof(GKaitaiEnum *));
+ kstruct->enums_count = count;
+
+ for (i = 0; i < count; i++)
+ {
+ kstruct->enums[i] = g_kaitai_enum_new(nodes[i]);
+ if (kstruct->enums[i] == NULL) 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)
+ goto bad_loading;
+
+ }
+
+ g_object_unref(G_OBJECT(collec));
+
+ }
+
+ /* Sortie heureuse */
+
+ result = true;
+
+ bad_loading:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = lecteur de définition à initialiser pleinement. *
+* *
+* Description : Charge les éventuelles dépendances de la définition. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_structure_load_imports(GKaitaiStruct *kstruct)
+{
+ bool result; /* Bilan d'opération à renvoyer*/
+ const char * const *dependencies; /* Liste d'imports requis */
+ size_t count; /* Quantité de ces imports */
+ size_t i; /* Boucle de parcours */
+ GKaitaiType *imported; /* Structure importée */
+
+ result = true;
+
+ dependencies = g_kaitai_meta_get_dependencies(kstruct->meta, &count);
+
+ for (i = 0; i < count; i++)
+ {
+ imported = import_kaitai_definition(dependencies[i], kstruct->filename);
+ if (imported == NULL) break;
+
+ kstruct->types_count++;
+ kstruct->types = realloc(kstruct->types, kstruct->types_count * sizeof(GKaitaiType *));
+
+ kstruct->types[kstruct->types_count - 1] = imported;
+
+ }
+
+ result = (i == count);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai à consulter. *
+* *
+* Description : Fournit la description globale d'une définition Kaitai. *
+* *
+* Retour : Description de la définition Kaitai courante. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiMeta *g_kaitai_structure_get_meta(const GKaitaiStruct *kstruct)
+{
+ GKaitaiMeta *result; /* Informations à retourner */
+
+ result = kstruct->meta;
+
+ if (result != NULL)
+ g_object_ref(G_OBJECT(result));
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* name = désignation principale des énumérations ciblées. *
+* *
+* Description : Fournit un ensemble d'énumérations locales de la structure. *
+* *
+* Retour : Enumérations locales ou NULL si non trouvée. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiEnum *g_kaitai_structure_get_enum(const GKaitaiStruct *kstruct, const sized_string_t *name)
+{
+ GKaitaiEnum *result; /* Instance à retourner */
+ size_t i; /* Boucle de parcours */
+ const char *other; /* Autre désignation à comparer*/
+
+ result = NULL;
+
+ for (i = 0; i < kstruct->enums_count; i++)
+ {
+ other = g_kaitai_enum_get_name(kstruct->enums[i]);
+
+ if (strncmp(name->data, other, name->len) == 0) // FIXME
+ {
+ result = kstruct->enums[i];
+ g_object_ref(G_OBJECT(result));
+ break;
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* name = désignation du type particulier ciblé. *
+* *
+* Description : Recherche la définition d'un type nouveau pour Kaitai. *
+* *
+* Retour : Type prêt à emploi ou NULL si non trouvé. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiType *g_kaitai_structure_find_sub_type(const GKaitaiStruct *kstruct, const char *name)
+{
+ GKaitaiType *result; /* Instance à retourner */
+ size_t i; /* Boucle de parcours */
+ const char *other; /* Autre désignation à comparer*/
+
+ result = NULL;
+
+ for (i = 0; i < kstruct->types_count; i++)
+ {
+ other = g_kaitai_type_get_name(kstruct->types[i]);
+
+ if (strcmp(name, other) == 0)
+ {
+ result = kstruct->types[i];
+ g_object_ref(G_OBJECT(result));
+ break;
+ }
+
+ result = g_kaitai_structure_find_sub_type(G_KAITAI_STRUCT(kstruct->types[i]), name);
+ if (result != NULL) break;
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* content = contenu binaire en cours de traitement. *
+* *
+* Description : Parcourt un contenu binaire selon une description Kaitai. *
+* *
+* Retour : Arborescence d'éléments rencontrés selon les spécifications. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *kstruct, GBinContent *content)
+{
+ GMatchRecord *result; /* Arborescence à retourner */
+ vmpa2t pos; /* Tête de lecture */
+ kaitai_scope_t locals; /* Variables locales */
+ ext_vmpa_t epos; /* Tête de lecture complète */
+
+ g_binary_content_compute_start_pos(content, &pos);
+
+ init_record_scope(&locals, kstruct->meta);
+
+ init_evmpa_from_vmpa(&epos, &pos);
+
+ g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct), &locals, content, &epos, &result);
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ GRecordGroup *group; /* Ensemble à constituer */
+ GMatchRecord *old; /* Sauvegarde de valeur */
+ size_t i; /* Boucle de parcours */
+ GMatchRecord *child; /* Nouvel élément mis en place */
+
+ result = true;
+
+ /* Si le groupe est vide */
+ if ((kstruct->seq_items_count + kstruct->instances_count) == 0)
+ {
+ *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(kstruct), content, &epos->base));
+
+ if (locals->root == NULL)
+ locals->root = *record;
+
+ }
+
+ /* Sinon on construit selon les définitions fournies */
+ else
+ {
+ group = g_record_group_new(kstruct, content);
+ *record = G_MATCH_RECORD(group);
+
+ if (locals->root == NULL)
+ locals->root = *record;
+
+ old = locals->parent;
+ locals->parent = *record;
+
+ /**
+ * Les instances sont à charger avant les éléments fixes car
+ * des références au premières peuvent être attendues dans ces derniers.
+ *
+ * Les évolutions de la tête de lecture n'ont en revanche normalement
+ * pas d'incidence sur le chargement des éléments fixes.
+ */
+
+ for (i = 0; i < kstruct->instances_count; i++)
+ {
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->instances[i]),
+ locals, content, epos, &child);
+ if (!result) goto exit;
+
+ if (child != NULL)
+ {
+ g_record_group_add_record(group, child);
+ g_object_unref(G_OBJECT(child));
+ }
+
+ }
+
+ /**
+ * Seconde phase.
+ */
+
+ locals->parent = *record;
+
+ for (i = 0; i < kstruct->seq_items_count; i++)
+ {
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->seq_items[i]),
+ locals, content, epos, &child);
+ if (!result) goto exit;
+
+ if (child != NULL)
+ {
+ g_record_group_add_record(group, child);
+ g_object_unref(G_OBJECT(child));
+ }
+
+ }
+
+ exit:
+
+ locals->parent = old;
+
+ if (!result)
+ g_clear_object(record);
+
+ }
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/struct.h b/plugins/kaitai/parsers/struct.h
new file mode 100644
index 0000000..4a2397a
--- /dev/null
+++ b/plugins/kaitai/parsers/struct.h
@@ -0,0 +1,80 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct.h - prototypes pour la définition d'une structure Kaitai
+ *
+ * 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_KAITAI_PARSERS_STRUCT_H
+#define _PLUGINS_KAITAI_PARSERS_STRUCT_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <analysis/content.h>
+
+
+#include "enum.h"
+#include "meta.h"
+#include "type.h"
+#include "../record.h"
+
+
+
+#define G_TYPE_KAITAI_STRUCT g_kaitai_structure_get_type()
+#define G_KAITAI_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_STRUCT, GKaitaiStruct))
+#define G_IS_KAITAI_STRUCT(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_STRUCT))
+#define G_KAITAI_STRUCT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_STRUCT, GKaitaiStructClass))
+#define G_IS_KAITAI_STRUCT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_STRUCT))
+#define G_KAITAI_STRUCT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_STRUCT, GKaitaiStructClass))
+
+
+/* Spécification d'une structure Kaitai (instance) */
+typedef struct _GKaitaiStruct GKaitaiStruct;
+
+/* Spécification d'une structure Kaitai (classe) */
+typedef struct _GKaitaiStructClass GKaitaiStructClass;
+
+
+/* Indique le type défini pour une structure Kaitai. */
+GType g_kaitai_structure_get_type(void);
+
+/* Crée un nouvel interpréteur de structure Kaitai. */
+GKaitaiStruct *g_kaitai_structure_new_from_text(const char *);
+
+/* Crée un nouvel interpréteur de structure Kaitai. */
+GKaitaiStruct *g_kaitai_structure_new_from_file(const char *);
+
+/* Fournit la description globale d'une définition Kaitai. */
+GKaitaiMeta *g_kaitai_structure_get_meta(const GKaitaiStruct *);
+
+/* Recherche la définition d'un type nouveau pour Kaitai. */
+GKaitaiType *g_kaitai_structure_find_sub_type(const GKaitaiStruct *, const char *);
+
+/* Fournit un ensemble d'énumérations locales de la structure. */
+GKaitaiEnum *g_kaitai_structure_get_enum(const GKaitaiStruct *, const sized_string_t *);
+
+/* Parcourt un contenu binaire selon une description Kaitai. */
+GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *, GBinContent *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_STRUCT_H */
diff --git a/plugins/kaitai/parsers/switch-int.h b/plugins/kaitai/parsers/switch-int.h
new file mode 100644
index 0000000..a087e49
--- /dev/null
+++ b/plugins/kaitai/parsers/switch-int.h
@@ -0,0 +1,78 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switch-int.h - prototypes internes pour la gestion des énumérations Kaitai
+ *
+ * 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_KAITAI_PARSERS_SWITCH_INT_H
+#define PLUGINS_KAITAI_PARSERS_SWITCH_INT_H
+
+
+#include "switch.h"
+#include "../parser-int.h"
+
+
+
+/* ------------------------ BASCULE DYNAMIQUE SELON CONTEXTE ------------------------ */
+
+
+/* Mémorisation d'une valeur d'énumération */
+typedef struct _switch_case_t
+{
+ char *value; /* Valeur d'association */
+ char *type; /* Désignation du type associé */
+
+} switch_case_t;
+
+
+
+/* ----------------------- SELECTION DYNAMIQUE DE TYPE KAITAI ----------------------- */
+
+
+/* Sélection d'un type selon un contexte (instance) */
+struct _GKaitaiSwitch
+{
+ GKaitaiParser parent; /* A laisser en premier */
+
+ char *target; /* Source de bascule */
+
+ switch_case_t **cases; /* Choix de types potentiels */
+ size_t count; /* Quantité de ces choix */
+
+ switch_case_t *defcase; /* Choix par défaut ou NULL */
+
+ GKaitaiAttribute *generic; /* Attribut à dériver */
+
+};
+
+/* Sélection d'un type selon un contexte (classe) */
+struct _GKaitaiSwitchClass
+{
+ GKaitaiParserClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place une sélection dynamique de type Kaitai. */
+bool g_kaitai_switch_create(GKaitaiSwitch *, GYamlNode *, GKaitaiAttribute *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_SWITCH_INT_H */
diff --git a/plugins/kaitai/parsers/switch.c b/plugins/kaitai/parsers/switch.c
new file mode 100644
index 0000000..6cfc96b
--- /dev/null
+++ b/plugins/kaitai/parsers/switch.c
@@ -0,0 +1,644 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switch.h - gestion des énumérations Kaitai
+ *
+ * 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 "switch.h"
+
+
+#include <assert.h>
+#include <errno.h>
+#include <malloc.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+#include <i18n.h>
+
+
+#include <common/extstr.h>
+#include <common/sort.h>
+#include <core/logs.h>
+#include <plugins/yaml/pair.h>
+
+
+#include "switch-int.h"
+#include "../expression.h"
+
+
+
+/* ------------------------ BASCULE DYNAMIQUE SELON CONTEXTE ------------------------ */
+
+
+/* Construit une valeur d'énumération à partir d'indications. */
+static switch_case_t *build_switch_case(const GYamlNode *, bool *);
+
+/* Supprime de la mémoire une bascule selon contexte. */
+static void delete_switch_case(switch_case_t *);
+
+/* Détermine si le cas correspond à une valeur de bascule. */
+static const char *is_suitable_switch_case_for_bytes(const switch_case_t *, const resolved_value_t *);
+
+/* Détermine si le cas correspond à une valeur de bascule. */
+static const char *is_suitable_switch_case_for_integer(const switch_case_t *, kaitai_scope_t *, const resolved_value_t *);
+
+
+
+/* ----------------------- SELECTION DYNAMIQUE DE TYPE KAITAI ----------------------- */
+
+
+/* Initialise la classe des sélections dynamiques de types. */
+static void g_kaitai_switch_class_init(GKaitaiSwitchClass *);
+
+/* Initialise une sélection dynamique de type Kaitai. */
+static void g_kaitai_switch_init(GKaitaiSwitch *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_switch_dispose(GKaitaiSwitch *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_switch_finalize(GKaitaiSwitch *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt un contenu binaire selon des spécifications Kaitai. */
+static bool g_kaitai_switch_parse_content(GKaitaiSwitch *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* BASCULE DYNAMIQUE SELON CONTEXTE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : node = noeud Yaml à venir lire. *
+* defcase = indique si une valeur par défaut est visée. [OUT] *
+* *
+* Description : Construit une valeur d'énumération à partir d'indications. *
+* *
+* Retour : Structure de valeur mise en place. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static switch_case_t *build_switch_case(const GYamlNode *node, bool *defcase)
+{
+ switch_case_t *result; /* Enregistrement à retourner */
+ const char *key; /* Clef d'une conversion */
+ const char *value; /* Valeur Yaml particulière */
+
+ result = NULL;
+
+ if (!G_IS_YAML_PAIR(node))
+ goto exit;
+
+ key = g_yaml_pair_get_key(G_YAML_PAIR(node));
+ value = g_yaml_pair_get_value(G_YAML_PAIR(node));
+
+ if (value == NULL)
+ goto exit;
+
+ result = malloc(sizeof(switch_case_t));
+
+ result->value = strdup(key);
+ result->type = strdup(value);
+
+ *defcase = (strcmp(key, "_") == 0);
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : swcase = valeur à traiter. *
+* *
+* Description : Supprime de la mémoire une bascule selon contexte. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+*****************************************************************************/
+
+static void delete_switch_case(switch_case_t *swcase)
+{
+ free(swcase->value);
+
+ free(swcase->type);
+
+ free(swcase);
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : swcase = valeur à analyser. *
+* value = valeur à comparer. *
+* *
+* Description : Détermine si le cas correspond à une valeur de bascule. *
+* *
+* Retour : Type à utiliser ou NULL si aucune correspondance établie. *
+* *
+* Remarques : - *
+* *
+*****************************************************************************/
+
+static const char *is_suitable_switch_case_for_bytes(const switch_case_t *swcase, const resolved_value_t *value)
+{
+ const char *result; /* Désignation à retourner */
+ sized_string_t key; /* Changement de format */
+ bool valid; /* Validité des opérations */
+ int ret; /* Bilan d'une comparaison */
+
+ result = NULL;
+
+ key.data = swcase->value;
+ key.len = strlen(swcase->value);
+
+ valid = (key.len > 2);
+
+ if (valid)
+ valid = (swcase->value[0] == '"' || swcase->value[0] == '\'');
+
+ if (valid)
+ {
+ valid = (key.data[0] == key.data[key.len - 1]);
+
+ key.data++;
+ key.len -= 2;
+
+ }
+
+ if (valid)
+ {
+ if (value->type == GVT_BYTES)
+ {
+ ret = szmemcmp(&key, &value->bytes);
+
+ if (ret == 0)
+ result = swcase->type;
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : swcase = valeur à analyser. *
+* locals = variables locales pour les résolutions de types. *
+* value = valeur à comparer. *
+* *
+* Description : Détermine si le cas correspond à une valeur de bascule. *
+* *
+* Retour : Type à utiliser ou NULL si aucune correspondance établie. *
+* *
+* Remarques : - *
+* *
+*****************************************************************************/
+
+static const char *is_suitable_switch_case_for_integer(const switch_case_t *swcase, kaitai_scope_t *locals, const resolved_value_t *value)
+{
+ const char *result; /* Désignation à retourner */
+ bool valid; /* Validité des opérations */
+ resolved_value_t key; /* Changement de format */
+ unsigned long long unsigned_conv; /* Valeur convertie #1 */
+ long long signed_conv; /* Valeur convertie #2 */
+
+ result = NULL;
+
+ valid = (swcase->value[0] != '"' && swcase->value[0] != '\'');
+
+ if (valid)
+ {
+ if (strchr(swcase->value, ':') != NULL)
+ {
+ valid = resolve_kaitai_expression_as_integer(locals, swcase->value, strlen(swcase->value), &key);
+
+ if (valid)
+ {
+ if (key.type == GVT_UNSIGNED_INTEGER)
+ {
+ if (value->type == GVT_UNSIGNED_INTEGER)
+ {
+ if (key.unsigned_integer == value->unsigned_integer)
+ result = swcase->type;
+ }
+ else
+ {
+ if (key.unsigned_integer == value->signed_integer)
+ result = swcase->type;
+ }
+ }
+ else
+ {
+ if (value->type == GVT_UNSIGNED_INTEGER)
+ {
+ if (key.signed_integer == value->unsigned_integer)
+ result = swcase->type;
+ }
+ else
+ {
+ if (key.signed_integer == value->signed_integer)
+ result = swcase->type;
+ }
+ }
+
+ }
+
+ }
+
+ else
+ {
+ if (value->type == GVT_UNSIGNED_INTEGER)
+ {
+ unsigned_conv = strtoull(swcase->value, NULL, 0);
+
+ valid = (errno != ERANGE && errno != EINVAL);
+
+ if (valid && unsigned_conv == value->unsigned_integer)
+ result = swcase->type;
+
+ }
+ else
+ {
+ signed_conv = strtoll(swcase->value, NULL, 0);
+
+ valid = (errno != ERANGE && errno != EINVAL);
+
+ if (valid && signed_conv == value->signed_integer)
+ result = swcase->type;
+
+ }
+
+ }
+
+ }
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* SELECTION DYNAMIQUE DE TYPE KAITAI */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un choix dynamique de type Kaitai. */
+G_DEFINE_TYPE(GKaitaiSwitch, g_kaitai_switch, G_TYPE_KAITAI_PARSER);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des sélections dynamiques de types. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_class_init(GKaitaiSwitchClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+ GKaitaiParserClass *parser; /* Version parente de la classe*/
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_switch_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_switch_finalize;
+
+ parser = G_KAITAI_PARSER_CLASS(klass);
+
+ parser->parse = (parse_kaitai_fc)g_kaitai_switch_parse_content;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = instance à initialiser. *
+* *
+* Description : Initialise une sélection dynamique de type Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_init(GKaitaiSwitch *kswitch)
+{
+ kswitch->target = NULL;
+
+ kswitch->cases = NULL;
+ kswitch->count = 0;
+
+ kswitch->defcase = NULL;
+
+ kswitch->generic = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_dispose(GKaitaiSwitch *kswitch)
+{
+ g_clear_object(&kswitch->generic);
+
+ G_OBJECT_CLASS(g_kaitai_switch_parent_class)->dispose(G_OBJECT(kswitch));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_switch_finalize(GKaitaiSwitch *kswitch)
+{
+ size_t i; /* Boucle de parcours */
+
+ if (kswitch->target != NULL)
+ free(kswitch->target);
+
+ for (i = 0; i < kswitch->count; i++)
+ delete_switch_case(kswitch->cases[i]);
+
+ if (kswitch->cases != NULL)
+ free(kswitch->cases);
+
+ if (kswitch->defcase != NULL)
+ delete_switch_case(kswitch->defcase);
+
+ G_OBJECT_CLASS(g_kaitai_switch_parent_class)->finalize(G_OBJECT(kswitch));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* generic = lecteur d'attribut Kaitai à dériver. *
+* *
+* Description : Construit une sélection dynamique de type Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiSwitch *g_kaitai_switch_new(GYamlNode *parent, GKaitaiAttribute *generic)
+{
+ GKaitaiSwitch *result; /* Identifiant à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_SWITCH, NULL);
+
+ if (!g_kaitai_switch_create(result, parent, generic))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = sélectionneur de type à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* generic = lecteur d'attribut Kaitai à dériver. *
+* *
+* Description : Met en place une sélection dynamique de type Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_switch_create(GKaitaiSwitch *kswitch, GYamlNode *parent, GKaitaiAttribute *generic)
+{
+ bool result; /* Bilan à retourner */
+ GYamlNode *node; /* Noeud de définition */
+ GYamlNode *subnode; /* Noeud de précisions */
+ const char *value; /* Valeur Yaml particulière */
+ GYamlNode *collec; /* Liste de noeuds à traiter */
+ GYamlNode **subnodes; /* Eventuels noeuds trouvés */
+ size_t count; /* Quantité de ces noeuds */
+ size_t i; /* Boucle de parcours */
+ bool defcase; /* Définition par défaut ? */
+ switch_case_t *swcase; /* Bascule à noter */
+
+ result = false;
+
+ node = g_yaml_node_find_first_by_path(parent, "/type/");
+ if (node == NULL) goto exit;
+
+ /* Source de la bascule */
+
+ subnode = g_yaml_node_find_first_by_path(node, "/switch-on");
+ assert(G_IS_YAML_PAIR(subnode));
+
+ value = g_yaml_pair_get_value(G_YAML_PAIR(subnode));
+ if (value == NULL)
+ {
+ g_object_unref(G_OBJECT(subnode));
+ goto bad_definition;
+ }
+
+ kswitch->target = strdup(value);
+
+ g_object_unref(G_OBJECT(subnode));
+
+ /* Conditions de bascule */
+
+ collec = g_yaml_node_find_first_by_path(node, "/cases/");
+ if (collec == NULL) goto bad_definition;
+ if (!G_IS_YAML_COLLEC(collec)) goto bad_definition;
+
+ subnodes = g_yaml_collection_get_nodes(G_YAML_COLLEC(collec), &count);
+
+ g_object_unref(G_OBJECT(collec));
+
+ if (count == 0) goto bad_definition;
+
+ for (i = 0; i < count; i++)
+ {
+ swcase = build_switch_case(subnodes[i], &defcase);
+ if (swcase == NULL) break;
+
+ g_object_unref(G_OBJECT(subnodes[i]));
+
+ kswitch->cases = realloc(kswitch->cases, ++kswitch->count * sizeof(switch_case_t *));
+ kswitch->cases[kswitch->count - 1] = swcase;
+
+ }
+
+ result = (i == count);
+
+ for (; i < count; i++)
+ g_object_unref(G_OBJECT(subnodes[i]));
+
+ if (subnodes != NULL)
+ free(subnodes);
+
+ /* Fin des procédures */
+
+ if (result)
+ {
+ kswitch->generic = generic;
+ g_object_ref(G_OBJECT(generic));
+ }
+
+ bad_definition:
+
+ g_object_unref(G_OBJECT(node));
+
+ exit:
+
+ return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+* *
+* Paramètres : kswitch = structure Kaitai en cours de parcours. *
+* locals = variables locales pour les résolutions de types. *
+* content = données binaires à analyser et traduire. *
+* epos = tête de lecture courante. [OUT] *
+* record = noeud d'arborescence d'éléments rencontrés. [OUT] *
+* *
+* Description : Parcourt un contenu binaire selon des spécifications Kaitai. *
+* *
+* Retour : Bilan de l'opératon : true pour continuer, false sinon. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static bool g_kaitai_switch_parse_content(GKaitaiSwitch *kswitch, kaitai_scope_t *locals, GBinContent *content, ext_vmpa_t *epos, GMatchRecord **record)
+{
+ bool result; /* Bilan à retourner */
+ const char *final_type; /* Type à utiliser au final */
+ resolved_value_t value; /* Valeur de cible entière */
+ bool status; /* Bilan intermédiaire */
+ size_t i; /* Boucle de parcours */
+ GKaitaiAttribute *attrib; /* Lecteur approprié */
+
+ result = true;
+
+ final_type = NULL;
+
+ /* Tenative n°1 : version "entier" */
+
+ status = resolve_kaitai_expression_as_integer(locals, kswitch->target, strlen(kswitch->target), &value);
+
+ if (status)
+ for (i = 0; i < kswitch->count; i++)
+ {
+ final_type = is_suitable_switch_case_for_integer(kswitch->cases[i], locals, &value);
+
+ if (final_type != NULL)
+ goto next_step;
+
+ }
+
+ status = resolve_kaitai_expression_as_bytes(locals, kswitch->target, strlen(kswitch->target), &value);
+
+ /* Tenative n°1 : version "chaîne" */
+
+ if (status)
+ for (i = 0; i < kswitch->count; i++)
+ {
+ final_type = is_suitable_switch_case_for_bytes(kswitch->cases[i], &value);
+
+ if (final_type != NULL)
+ goto next_step;
+
+ }
+
+ if (final_type == NULL && kswitch->defcase != NULL)
+ final_type = kswitch->defcase->type;
+
+ next_step:
+
+ /* Mise en place d'un attribut et analyse */
+
+ if (final_type != NULL)
+ {
+ attrib = g_kaitai_attribute_dup_for_user_type(kswitch->generic, final_type);
+
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib), locals, content, epos, record);
+
+ g_object_unref(G_OBJECT(attrib));
+
+ }
+
+ return true;
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/switch.h b/plugins/kaitai/parsers/switch.h
new file mode 100644
index 0000000..c45237a
--- /dev/null
+++ b/plugins/kaitai/parsers/switch.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * switch.h - prototypes pour la gestion des énumérations Kaitai
+ *
+ * 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_KAITAI_PARSERS_SWITCH_H
+#define _PLUGINS_KAITAI_PARSERS_SWITCH_H
+
+
+#include <glib-object.h>
+
+
+#include <plugins/yaml/node.h>
+
+
+#include "attribute.h"
+
+
+
+#define G_TYPE_KAITAI_SWITCH g_kaitai_switch_get_type()
+#define G_KAITAI_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_SWITCH, GKaitaiSwitch))
+#define G_IS_KAITAI_SWITCH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_SWITCH))
+#define G_KAITAI_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_SWITCH, GKaitaiSwitchClass))
+#define G_IS_KAITAI_SWITCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_SWITCH))
+#define G_KAITAI_SWITCH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_SWITCH, GKaitaiSwitchClass))
+
+
+/* Sélection d'un type selon un contexte (instance) */
+typedef struct _GKaitaiSwitch GKaitaiSwitch;
+
+/* Sélection d'un type selon un contexte (classe) */
+typedef struct _GKaitaiSwitchClass GKaitaiSwitchClass;
+
+
+/* Indique le type défini pour un choix dynamique de type Kaitai. */
+GType g_kaitai_switch_get_type(void);
+
+/* Construit une sélection dynamique de type Kaitai. */
+GKaitaiSwitch *g_kaitai_switch_new(GYamlNode *, GKaitaiAttribute *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_SWITCH_H */
diff --git a/plugins/kaitai/parsers/type-int.h b/plugins/kaitai/parsers/type-int.h
new file mode 100644
index 0000000..535ce57
--- /dev/null
+++ b/plugins/kaitai/parsers/type-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type-int.h - prototypes internes pour la définition d'un type particulier pour Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef PLUGINS_KAITAI_PARSERS_TYPE_INT_H
+#define PLUGINS_KAITAI_PARSERS_TYPE_INT_H
+
+
+#include "struct-int.h"
+#include "type.h"
+
+
+
+/* Définition d'un type particulier nouveau pour Kaitai (instance) */
+struct _GKaitaiType
+{
+ GKaitaiStruct parent; /* A laisser en premier */
+
+ char *name; /* Nom du type particulier */
+
+};
+
+/* Définition d'un type particulier nouveau pour Kaitai (classe) */
+struct _GKaitaiTypeClass
+{
+ GKaitaiStructClass parent; /* A laisser en premier */
+
+};
+
+
+/* Met en place un lecteur de type pour Kaitai. */
+bool g_kaitai_type_create(GKaitaiType *, GYamlNode *);
+
+/* Met en place un lecteur de type externe pour Kaitai. */
+bool g_kaitai_type_create_as_import(GKaitaiType *, const char *, const char *);
+
+
+
+#endif /* PLUGINS_KAITAI_PARSERS_TYPE_INT_H */
diff --git a/plugins/kaitai/parsers/type.c b/plugins/kaitai/parsers/type.c
new file mode 100644
index 0000000..81efbeb
--- /dev/null
+++ b/plugins/kaitai/parsers/type.c
@@ -0,0 +1,294 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * struct.c - définition d'une structure Kaitai
+ *
+ * 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 "type.h"
+
+
+#include <malloc.h>
+#include <string.h>
+#include <plugins/yaml/pair.h>
+
+
+#include "type-int.h"
+#include "../parser.h"
+
+
+
+/* Initialise la classe des types particuliers pour Kaitai. */
+static void g_kaitai_type_class_init(GKaitaiTypeClass *);
+
+/* Initialise un type particulier pour Kaitai. */
+static void g_kaitai_type_init(GKaitaiType *);
+
+/* Supprime toutes les références externes. */
+static void g_kaitai_type_dispose(GKaitaiType *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_kaitai_type_finalize(GKaitaiType *);
+
+
+
+/* Indique le type défini pour un type particulier pour Kaitai. */
+G_DEFINE_TYPE(GKaitaiType, g_kaitai_type, G_TYPE_KAITAI_STRUCT);
+
+
+/******************************************************************************
+* *
+* Paramètres : klass = classe à initialiser. *
+* *
+* Description : Initialise la classe des types particuliers pour Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_type_class_init(GKaitaiTypeClass *klass)
+{
+ GObjectClass *object; /* Autre version de la classe */
+
+ object = G_OBJECT_CLASS(klass);
+
+ object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_type_dispose;
+ object->finalize = (GObjectFinalizeFunc)g_kaitai_type_finalize;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : kstruct = instance à initialiser. *
+* *
+* Description : Initialise un type particulier pour Kaitai. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_type_init(GKaitaiType *type)
+{
+ type->name = NULL;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = instance d'objet GLib à traiter. *
+* *
+* Description : Supprime toutes les références externes. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_type_dispose(GKaitaiType *type)
+{
+ G_OBJECT_CLASS(g_kaitai_type_parent_class)->dispose(G_OBJECT(type));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = instance d'objet GLib à traiter. *
+* *
+* Description : Procède à la libération totale de la mémoire. *
+* *
+* Retour : - *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static void g_kaitai_type_finalize(GKaitaiType *type)
+{
+ if (type->name != NULL)
+ free(type->name);
+
+ G_OBJECT_CLASS(g_kaitai_type_parent_class)->finalize(G_OBJECT(type));
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Construit un lecteur de type pour Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiType *g_kaitai_type_new(GYamlNode *parent)
+{
+ GKaitaiType *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_TYPE, NULL);
+
+ if (!g_kaitai_type_create(result, parent))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = lecteur de type Kaitai à initialiser pleinement. *
+* parent = noeud Yaml contenant l'attribut à constituer. *
+* *
+* Description : Met en place un lecteur de type pour Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_type_create(GKaitaiType *type, GYamlNode *parent)
+{
+ bool result; /* Bilan à retourner */
+ const char *name; /* Désignation du type */
+ char *sub_path; /* Chemin d'accès suivant */
+ GYamlNode *sub; /* Contenu Yaml d'un type */
+
+ result = false;
+
+ /* Extraction du nom */
+
+ if (!G_IS_YAML_PAIR(parent))
+ goto exit;
+
+ name = g_yaml_pair_get_key(G_YAML_PAIR(parent));
+
+ type->name = strdup(name);
+
+ /* Extraction des bases du type */
+
+ asprintf(&sub_path, "/%s/", name);
+ sub = g_yaml_node_find_first_by_path(parent, sub_path);
+ free(sub_path);
+
+ if (sub == NULL)
+ goto exit;
+
+ result = g_kaitai_structure_create(G_KAITAI_STRUCT(type), sub);
+
+ g_object_unref(G_OBJECT(sub));
+
+ exit:
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : name = nom à attribuer au futur type. *
+* filename = chemin vers une définition Kaitai à charger. *
+* *
+* Description : Construit un lecteur de type externe pour Kaitai. *
+* *
+* Retour : Instance mise en place ou NULL en cas d'échec. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+GKaitaiType *g_kaitai_type_new_as_import(const char *name, const char *filename)
+{
+ GKaitaiType *result; /* Structure à retourner */
+
+ result = g_object_new(G_TYPE_KAITAI_TYPE, NULL);
+
+ if (!g_kaitai_type_create_as_import(result, name, filename))
+ g_clear_object(&result);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = lecteur de type Kaitai à initialiser pleinement. *
+* name = nom à attribuer au futur type. *
+* filename = chemin vers une définition Kaitai à charger. *
+* *
+* Description : Met en place un lecteur de type externe pour Kaitai. *
+* *
+* Retour : Bilan de l'opération. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+bool g_kaitai_type_create_as_import(GKaitaiType *type, const char *name, const char *filename)
+{
+ bool result; /* Bilan à retourner */
+
+ /* Extraction du nom */
+
+ type->name = strdup(name);
+
+ /* Extraction des bases du type */
+
+ result = g_kaitai_structure_create_from_file(G_KAITAI_STRUCT(type), filename);
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : type = définition de type particulier à consulter. *
+* *
+* Description : Indique le nom de scène du type représenté. *
+* *
+* Retour : Désignation humaine. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+const char *g_kaitai_type_get_name(const GKaitaiType *type)
+{
+ const char *result; /* Nom à retourner */
+
+ result = type->name;
+
+ return result;
+
+}
diff --git a/plugins/kaitai/parsers/type.h b/plugins/kaitai/parsers/type.h
new file mode 100644
index 0000000..d19ab90
--- /dev/null
+++ b/plugins/kaitai/parsers/type.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * type.h - prototypes pour la définition d'un type particulier pour Kaitai
+ *
+ * Copyright (C) 2023 Cyrille Bagard
+ *
+ * This file is part of Chrysalide.
+ *
+ * Chrysalide is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Chrysalide is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _PLUGINS_KAITAI_PARSERS_TYPE_H
+#define _PLUGINS_KAITAI_PARSERS_TYPE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include <plugins/yaml/node.h>
+
+
+
+#define G_TYPE_KAITAI_TYPE g_kaitai_type_get_type()
+#define G_KAITAI_TYPE(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_KAITAI_TYPE, GKaitaiType))
+#define G_IS_KAITAI_TYPE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_KAITAI_TYPE))
+#define G_KAITAI_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_KAITAI_TYPE, GKaitaiTypeClass))
+#define G_IS_KAITAI_TYPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_KAITAI_TYPE))
+#define G_KAITAI_TYPE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_KAITAI_TYPE, GKaitaiTypeClass))
+
+
+/* Définition d'un type particulier nouveau pour Kaitai (instance) */
+typedef struct _GKaitaiType GKaitaiType;
+
+/* Définition d'un type particulier nouveau pour Kaitai (classe) */
+typedef struct _GKaitaiTypeClass GKaitaiTypeClass;
+
+
+/* Indique le type défini pour un type particulier pour Kaitai. */
+GType g_kaitai_type_get_type(void);
+
+/* Construit un lecteur de type pour Kaitai. */
+GKaitaiType *g_kaitai_type_new(GYamlNode *);
+
+/* Construit un lecteur de type externe pour Kaitai. */
+GKaitaiType *g_kaitai_type_new_as_import(const char *, const char *);
+
+/* Indique le nom de scène du type représenté. */
+const char *g_kaitai_type_get_name(const GKaitaiType *);
+
+
+
+#endif /* _PLUGINS_KAITAI_PARSERS_TYPE_H */