summaryrefslogtreecommitdiff
path: root/plugins/kaitai/parsers
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2023-10-09 22:49:59 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2023-10-09 22:49:59 (GMT)
commit7c6fe94c90d320813d0d78a9dbef707696f31505 (patch)
tree912b5c51469c02e6ef680c0c60739787ccff4891 /plugins/kaitai/parsers
parentcb05b99a8c451ff80d88f988e2654c794b0f3750 (diff)
Support some last missing features from Kaitai: bit fields, instance search order and stream EOF.
Diffstat (limited to 'plugins/kaitai/parsers')
-rw-r--r--plugins/kaitai/parsers/attribute-int.h3
-rw-r--r--plugins/kaitai/parsers/attribute.c206
-rw-r--r--plugins/kaitai/parsers/attribute.h20
-rw-r--r--plugins/kaitai/parsers/instance.c149
-rw-r--r--plugins/kaitai/parsers/instance.h3
-rw-r--r--plugins/kaitai/parsers/struct.c45
-rw-r--r--plugins/kaitai/parsers/switch.c112
7 files changed, 342 insertions, 196 deletions
diff --git a/plugins/kaitai/parsers/attribute-int.h b/plugins/kaitai/parsers/attribute-int.h
index ef64089..7d37af3 100644
--- a/plugins/kaitai/parsers/attribute-int.h
+++ b/plugins/kaitai/parsers/attribute-int.h
@@ -51,6 +51,9 @@ struct _GKaitaiAttribute
/* 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
{
diff --git a/plugins/kaitai/parsers/attribute.c b/plugins/kaitai/parsers/attribute.c
index 58d8dd1..d0505d8 100644
--- a/plugins/kaitai/parsers/attribute.c
+++ b/plugins/kaitai/parsers/attribute.c
@@ -25,6 +25,7 @@
#include <assert.h>
+#include <stdlib.h>
#include <string.h>
@@ -35,6 +36,7 @@
#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"
@@ -56,6 +58,9 @@ 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 *);
@@ -71,7 +76,7 @@ static GKaitaiAttribute *g_kaitai_attribute_dup_for(const GKaitaiAttribute *);
/* Parcourt un contenu binaire selon des spécifications Kaitai. */
-static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, vmpa2t *, GMatchRecord **);
+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 **);
@@ -80,7 +85,7 @@ static bool g_kaitai_attribute_parse_terminated_bytes(GKaitaiAttribute *, const
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 *, vmpa2t *, GMatchRecord **);
+static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
@@ -399,7 +404,10 @@ bool g_kaitai_attribute_create(GKaitaiAttribute *attrib, GYamlNode *parent, bool
if (value != NULL)
{
- if (g_kaitai_attribute_resolve_type(attrib, value))
+ 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
@@ -701,6 +709,54 @@ bool g_kaitai_attribute_create(GKaitaiAttribute *attrib, GYamlNode *parent, bool
* 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. *
@@ -930,7 +986,7 @@ static bool g_kaitai_attribute_check(const GKaitaiAttribute *attrib)
}
/**
- * Si une séquence d'octets finaux est spécifiées, alors l'attribut
+ * 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).
*/
@@ -1429,6 +1485,50 @@ bool g_kaitai_attribute_read_value(const GKaitaiAttribute *attrib, const GBinCon
}
+/******************************************************************************
+* *
+* 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 */
@@ -1440,7 +1540,7 @@ bool g_kaitai_attribute_read_value(const GKaitaiAttribute *attrib, const GBinCon
* 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] *
+* 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. *
@@ -1451,7 +1551,7 @@ bool g_kaitai_attribute_read_value(const GKaitaiAttribute *attrib, const GBinCon
* *
******************************************************************************/
-static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, vmpa2t *pos, GMatchRecord **record)
+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 */
@@ -1483,6 +1583,10 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
result = false;
*record = NULL;
+ printf("\n");
+ printf("------------parsing %s -( payload: %x - ut=%d )-----------\n",
+ attrib->raw_id, attrib->payload, attrib->payload & KAP_USER_TYPE);
+
/* Lecture soumise à condition ? */
if (attrib->condition != NULL)
@@ -1492,6 +1596,8 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
strlen(attrib->condition),
&authorized);
+ printf("condition '%s': res=%d auth=%d\n", attrib->condition, result, authorized.status);
+
if (!result || !authorized.status)
goto exit;
@@ -1500,7 +1606,10 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
/* Zone de travail restreinte */
g_binary_content_compute_end_pos(content, &tmp);
- diff = compute_vmpa_diff(pos, &tmp);
+ diff = compute_vmpa_diff(&epos->base, &tmp);
+
+ if (epos->consumed_extra_bits > 0 && diff > 0)
+ diff--;
if (attrib->payload & KAP_SIZED)
{
@@ -1538,7 +1647,9 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
if (!result)
goto exit;
- init_mrange(&work_range, pos, diff);
+ 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);
@@ -1553,16 +1664,24 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
/* Etablissement d'une zone de correspondance */
if (attrib->payload == KAP_UNINITIALIZED)
- assert(false);
+ {
+ printf("attrib: '%s'\n", attrib->raw_id);
+ //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)
{
- copy_vmpa(&tmp, pos);
+ 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);
@@ -1576,8 +1695,26 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
}
+ 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:
@@ -1585,7 +1722,8 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
if (attrib->is_string)
{
if ((attrib->payload & KAP_SIZED) == 0)
- result = g_kaitai_attribute_parse_terminated_bytes(attrib, locals, work_area, pos, record);
+ result = g_kaitai_attribute_parse_terminated_bytes(attrib, locals,
+ work_area, &epos->base, record);
}
else
{
@@ -1625,10 +1763,13 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
{
user_type = find_sub_type(locals, attrib->named_type);
+ printf(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> find '%s' => %p\n",
+ attrib->named_type, user_type);
+
if (user_type != NULL)
{
result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(user_type),
- locals, work_area, pos, record);
+ locals, work_area, epos, record);
if (result)
/**
@@ -1648,7 +1789,7 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
}
else if (attrib->payload & KAP_DYNAMIC_TYPE)
- result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib->switchon), locals, work_area, pos, record);
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib->switchon), locals, work_area, epos, record);
else if (attrib->payload & KAP_SIZED)
{
@@ -1661,6 +1802,11 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
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
@@ -1669,12 +1815,13 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
/* if (diff > 0) */
{
- result = g_kaitai_attribute_compute_maybe_terminated_range(attrib, locals, content, pos, &diff, &range);
+ 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, pos));
+ *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(attrib), content, &epos->base));
else
{
@@ -1686,7 +1833,7 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
*record = G_MATCH_RECORD(g_record_item_new(attrib, work_area, &range, endian));
if (*record != NULL)
- advance_vmpa(pos, diff);
+ advance_vmpa(&epos->base, diff);
else
result = false;
@@ -1702,13 +1849,16 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
if (attrib->payload & KAP_SIZED)
{
- cur_diff = compute_vmpa_diff(get_mrange_addr(&work_range), pos);
+ /* 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(pos, max_size - cur_diff);
+ advance_vmpa(&epos->base, max_size - cur_diff);
assert(work_area != content);
g_object_unref(G_OBJECT(work_area));
@@ -1717,6 +1867,8 @@ static bool _g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_s
exit:
+ printf(" ===[[ %s / %p ]]=== >> %d\n", attrib->raw_id, attrib, result);
+
return result;
}
@@ -1933,7 +2085,7 @@ static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttri
* 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] *
+* 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. *
@@ -1944,7 +2096,7 @@ static bool g_kaitai_attribute_compute_maybe_terminated_range(const GKaitaiAttri
* *
******************************************************************************/
-static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_scope_t *locals, GBinContent *content, vmpa2t *pos, GMatchRecord **record)
+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 */
@@ -1958,7 +2110,7 @@ static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_sc
resolved_value_t loop; /* Poursuite des lectures ? */
if (attrib->repetition == KAR_NO_REPETITION)
- result = _g_kaitai_attribute_parse_content(attrib, locals, content, pos, record);
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, record);
else
{
@@ -1976,7 +2128,7 @@ static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_sc
}
- list = g_record_list_new(attrib, content, pos);
+ list = g_record_list_new(attrib, content, &epos->base);
switch (attrib->repetition)
{
@@ -1985,17 +2137,17 @@ static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_sc
result = true;
g_binary_content_compute_end_pos(content, &end);
- diff = compute_vmpa_diff(pos, &end);
+ diff = compute_vmpa_diff(&epos->base, &end);
while (diff > 0)
{
- result = _g_kaitai_attribute_parse_content(attrib, locals, content, pos, &child);
+ 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(pos, &end);
+ diff = compute_vmpa_diff(&epos->base, &end);
}
@@ -2026,7 +2178,7 @@ static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_sc
for (i = 0; i < count; i++)
{
- result = _g_kaitai_attribute_parse_content(attrib, locals, content, pos, &child);
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
if (!result) break;
g_record_list_add_record(list, child);
@@ -2040,7 +2192,7 @@ static bool g_kaitai_attribute_parse_content(GKaitaiAttribute *attrib, kaitai_sc
do
{
- result = _g_kaitai_attribute_parse_content(attrib, locals, content, pos, &child);
+ result = _g_kaitai_attribute_parse_content(attrib, locals, content, epos, &child);
if (!result) break;
g_record_list_add_record(list, child);
diff --git a/plugins/kaitai/parsers/attribute.h b/plugins/kaitai/parsers/attribute.h
index 38b78d7..9b43936 100644
--- a/plugins/kaitai/parsers/attribute.h
+++ b/plugins/kaitai/parsers/attribute.h
@@ -56,18 +56,19 @@ typedef struct _GKaitaiAttributeClass GKaitaiAttributeClass;
/* Type de charge associée à un attribut */
typedef enum _KaitaiAttributePayload
{
- KAP_UNINITIALIZED = (0 << 0), /* Type non initialisé */
+ KAP_UNINITIALIZED = (0 << 0), /* Type non initialisé */
- KAP_FIXED_CONTENT = (1 << 0), /* Contenu brut attendu */
- KAP_BASIC_TYPE = (1 << 1), /* Type prédéfini */
- KAP_USER_TYPE = (1 << 2), /* Type personnalisé */
- KAP_DYNAMIC_TYPE = (1 << 3), /* Type dynmatique */
- KAP_SIZED = (1 << 4), /* Bourrage dimensionné */
- KAP_SIZED_EOS = (1 << 5), /* Bourrage final */
+ 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 */
+/* Types de base reconnus par Kaitai */ /* TODO : REMME ? (car non utilisé) */
typedef enum _KaitaiBasicType
{
KBT_U1, /* Octet non signé */
@@ -149,6 +150,9 @@ 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/instance.c b/plugins/kaitai/parsers/instance.c
index 63db224..d62c1f6 100644
--- a/plugins/kaitai/parsers/instance.c
+++ b/plugins/kaitai/parsers/instance.c
@@ -34,7 +34,7 @@
#include "instance-int.h"
#include "../expression.h"
-#include "../records/value.h"
+#include "../records/delayed.h"
@@ -59,7 +59,7 @@ static void g_kaitai_instance_finalize(GKaitaiInstance *);
/* Parcourt un contenu binaire selon des spécifications Kaitai. */
-static bool g_kaitai_instance_parse_content(GKaitaiInstance *, kaitai_scope_t *, GBinContent *, vmpa2t *, GMatchRecord **);
+static bool g_kaitai_instance_parse_content(GKaitaiInstance *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
@@ -349,74 +349,30 @@ const char *g_kaitai_instance_get_name(const GKaitaiInstance *inst)
* *
* 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]*
+* content = contenu binaire lié à la correspondance. *
* *
-* Description : Détermine la valeur d'un élément Kaitai entier calculé. *
+* Description : Détermine la valeur effective d'un élément Kaitai dynamique. *
* *
-* Retour : Bilan de l'opération. *
+* Retour : valeur à sauvegarder sous une forme générique. *
* *
* Remarques : - *
* *
******************************************************************************/
-bool g_kaitai_instance_compute_value(const GKaitaiInstance *inst, const kaitai_scope_t *locals, resolved_value_t *value)
+GMatchRecord *g_kaitai_instance_compute_real_record(const GKaitaiInstance *inst, const kaitai_scope_t *locals, GBinContent *content)
{
- 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. *
-* pos = 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, vmpa2t *pos, GMatchRecord **record)
-{
- bool result; /* Bilan à retourner */
+ GMatchRecord *result; /* Enregistrement à retourner */
GBinContent *work_area; /* Aire de travail */
GKaitaiStream *stream; /* Flux de données pour Kaitai */
- resolved_value_t offset; /* Position à adopter */
+ 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 */
- if (inst->value != NULL)
- {
- *record = G_MATCH_RECORD(g_record_value_new(inst, locals));
+ result = NULL;
- result = (*record != NULL);
-
- }
-
- else
+ if (inst->value == NULL)
{
/* Contenu particulier */
@@ -425,8 +381,8 @@ static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_
else
{
- result = resolve_kaitai_expression_as_stream(locals, inst->io, strlen(inst->io), &stream);
- if (!result) goto exit;
+ 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);
@@ -438,8 +394,8 @@ static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_
g_binary_content_compute_start_pos(work_area, &forced_pos);
- result = resolve_kaitai_expression_as_integer(locals, inst->pos, strlen(inst->pos), &offset);
- if (!result) goto exit_with_content;
+ 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);
@@ -450,7 +406,7 @@ static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_
if (offset.signed_integer < 0)
{
- result = false;
+ status = false;
goto exit_with_content;
}
@@ -462,7 +418,9 @@ static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_
class = G_KAITAI_PARSER_CLASS(g_kaitai_instance_parent_class);
- result = class->parse(G_KAITAI_PARSER(inst), locals, work_area, &forced_pos, record);
+ init_evmpa_from_vmpa(&epos, &forced_pos);
+
+ class->parse(G_KAITAI_PARSER(inst), locals, work_area, &epos, &result);
exit_with_content:
@@ -476,3 +434,70 @@ static bool g_kaitai_instance_parse_content(GKaitaiInstance *inst, kaitai_scope_
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
index a9aee9a..4594137 100644
--- a/plugins/kaitai/parsers/instance.h
+++ b/plugins/kaitai/parsers/instance.h
@@ -60,6 +60,9 @@ 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 *);
diff --git a/plugins/kaitai/parsers/struct.c b/plugins/kaitai/parsers/struct.c
index f23a264..62dc25a 100644
--- a/plugins/kaitai/parsers/struct.c
+++ b/plugins/kaitai/parsers/struct.c
@@ -64,7 +64,7 @@ static bool g_kaitai_structure_load_imports(GKaitaiStruct *);
/* Parcourt un contenu binaire selon des spécifications Kaitai. */
-static bool g_kaitai_structure_parse_content(GKaitaiStruct *, kaitai_scope_t *, GBinContent *, vmpa2t *, GMatchRecord **);
+static bool g_kaitai_structure_parse_content(GKaitaiStruct *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
@@ -712,13 +712,17 @@ GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *kstruct, GBinContent *cont
GMatchRecord *result; /* Arborescence à retourner */
vmpa2t pos; /* Tête de lecture */
kaitai_scope_t locals; /* Variables locales */
- bool status; /* Bilan de l'analyse */
+ ext_vmpa_t epos; /* Tête de lecture complète */
g_binary_content_compute_start_pos(content, &pos);
init_record_scope(&locals, kstruct->meta);
- status = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct), &locals, content, &pos, &result);
+ init_evmpa_from_vmpa(&epos, &pos);
+
+ g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct), &locals, content, &epos, &result);
+
+ printf("FINAL STATUS :: %d\n", result != NULL);
return result;
@@ -736,7 +740,7 @@ GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *kstruct, GBinContent *cont
* 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. *
-* pos = tête de lecture courante. [OUT] *
+* 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. *
@@ -747,7 +751,7 @@ GMatchRecord *g_kaitai_structure_parse(GKaitaiStruct *kstruct, GBinContent *cont
* *
******************************************************************************/
-static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scope_t *locals, GBinContent *content, vmpa2t *pos, GMatchRecord **record)
+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 */
@@ -760,7 +764,7 @@ static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scop
/* 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, pos));
+ *record = G_MATCH_RECORD(g_record_empty_new(G_KAITAI_PARSER(kstruct), content, &epos->base));
if (locals->root == NULL)
locals->root = *record;
@@ -779,10 +783,18 @@ static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scop
old = locals->parent;
locals->parent = *record;
- for (i = 0; i < kstruct->seq_items_count; i++)
+ /**
+ * 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->seq_items[i]),
- locals, content, pos, &child);
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->instances[i]),
+ locals, content, epos, &child);
if (!result) goto exit;
if (child != NULL)
@@ -793,10 +805,16 @@ static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scop
}
- for (i = 0; i < kstruct->instances_count; i++)
+ /**
+ * Seconde phase.
+ */
+
+ locals->parent = *record;
+
+ for (i = 0; i < kstruct->seq_items_count; i++)
{
- result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->instances[i]),
- locals, content, pos, &child);
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(kstruct->seq_items[i]),
+ locals, content, epos, &child);
if (!result) goto exit;
if (child != NULL)
@@ -811,6 +829,9 @@ static bool g_kaitai_structure_parse_content(GKaitaiStruct *kstruct, kaitai_scop
locals->parent = old;
+ if (!result)
+ g_clear_object(record);
+
}
return result;
diff --git a/plugins/kaitai/parsers/switch.c b/plugins/kaitai/parsers/switch.c
index c823f27..6cfc96b 100644
--- a/plugins/kaitai/parsers/switch.c
+++ b/plugins/kaitai/parsers/switch.c
@@ -83,7 +83,7 @@ static void g_kaitai_switch_finalize(GKaitaiSwitch *);
/* Parcourt un contenu binaire selon des spécifications Kaitai. */
-static bool g_kaitai_switch_parse_content(GKaitaiSwitch *, kaitai_scope_t *, GBinContent *, vmpa2t *, GMatchRecord **);
+static bool g_kaitai_switch_parse_content(GKaitaiSwitch *, kaitai_scope_t *, GBinContent *, ext_vmpa_t *, GMatchRecord **);
@@ -285,7 +285,7 @@ static const char *is_suitable_switch_case_for_integer(const switch_case_t *swca
{
if (value->type == GVT_UNSIGNED_INTEGER)
{
- unsigned_conv = strtoull(swcase->value, NULL, 10);
+ unsigned_conv = strtoull(swcase->value, NULL, 0);
valid = (errno != ERANGE && errno != EINVAL);
@@ -295,7 +295,7 @@ static const char *is_suitable_switch_case_for_integer(const switch_case_t *swca
}
else
{
- signed_conv = strtoll(swcase->value, NULL, 10);
+ signed_conv = strtoll(swcase->value, NULL, 0);
valid = (errno != ERANGE && errno != EINVAL);
@@ -569,7 +569,7 @@ bool g_kaitai_switch_create(GKaitaiSwitch *kswitch, GYamlNode *parent, GKaitaiAt
* 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. *
-* pos = tête de lecture courante. [OUT] *
+* 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. *
@@ -580,127 +580,65 @@ bool g_kaitai_switch_create(GKaitaiSwitch *kswitch, GYamlNode *parent, GKaitaiAt
* *
******************************************************************************/
-static bool g_kaitai_switch_parse_content(GKaitaiSwitch *kswitch, kaitai_scope_t *locals, GBinContent *content, vmpa2t *pos, GMatchRecord **record)
+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 */
- GMatchRecord *reference; /* Correspondance à utiliser */
- GKaitaiParser *creator; /* Lecteur d'origine */
- KaitaiAttributePayload payload; /* Type de charge supportée */
- BaseType basic; /* Type de base reconnu */
- bool is_string; /* Type lié à une chaîne ? */
-#ifndef NDEBUG
- bool status; /* Bilan d'une consultation */
-#endif
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 = false;
-
- /* Détermination de la forme de comparaison */
-
- reference = g_match_record_find_by_name(locals->parent,
- kswitch->target, strlen(kswitch->target),
- DIRECT_SEARCH_DEEP_LEVEL);
-
- if (reference == NULL)
- goto exit;
-
- creator = g_match_record_get_creator(reference);
-
- if (creator == NULL)
- goto exit_with_ref;
-
- if (!G_IS_KAITAI_ATTRIBUTE(creator))
- goto exit_with_creator;
-
- payload = g_kaitai_attribute_get_payload(G_KAITAI_ATTRIBUTE(creator));
-
- if ((payload & KAP_BASIC_TYPE) == 0)
- goto exit_with_creator;
-
-#ifndef NDEBUG
- status = g_kaitai_attribute_get_basic_type(G_KAITAI_ATTRIBUTE(creator), &basic, &is_string);
- assert(status);
-#else
- g_kaitai_attribute_get_basic_type(G_KAITAI_ATTRIBUTE(creator), &basic, &is_string);
-#endif
-
- /* Détermination du type visé */
+ result = true;
final_type = NULL;
- if (is_string)
- {
- result = resolve_kaitai_expression_as_bytes(locals,
- kswitch->target,
- strlen(kswitch->target),
- &value);
- if (!result) goto exit_with_creator;
+ /* 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_bytes(kswitch->cases[i], &value);
+ final_type = is_suitable_switch_case_for_integer(kswitch->cases[i], locals, &value);
if (final_type != NULL)
- break;
+ goto next_step;
}
- }
-
- else
- {
- if (basic == BTP_UCHAR || basic == BTP_USHORT || basic == BTP_UINT || basic == BTP_ULONG_LONG)
- {
- result = resolve_kaitai_expression_as_integer(locals,
- kswitch->target,
- strlen(kswitch->target),
- &value);
- if (!result) goto exit_with_creator;
+ status = resolve_kaitai_expression_as_bytes(locals, kswitch->target, strlen(kswitch->target), &value);
- for (i = 0; i < kswitch->count; i++)
- {
- final_type = is_suitable_switch_case_for_integer(kswitch->cases[i], locals, &value);
+ /* Tenative n°1 : version "chaîne" */
- if (final_type != NULL)
- break;
+ 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;
}
- else
- printf("other type: %u\n", basic);
-
- }
-
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, pos, record);
+ result = g_kaitai_parser_parse_content(G_KAITAI_PARSER(attrib), locals, content, epos, record);
g_object_unref(G_OBJECT(attrib));
}
- exit_with_creator:
-
- g_object_unref(G_OBJECT(creator));
-
- exit_with_ref:
-
- g_object_unref(G_OBJECT(reference));
-
- exit:
-
+ return true;
return result;
}