summaryrefslogtreecommitdiff
path: root/plugins/kaitai/parsers/attribute.c
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/attribute.c
parentcb05b99a8c451ff80d88f988e2654c794b0f3750 (diff)
Support some last missing features from Kaitai: bit fields, instance search order and stream EOF.
Diffstat (limited to 'plugins/kaitai/parsers/attribute.c')
-rw-r--r--plugins/kaitai/parsers/attribute.c206
1 files changed, 179 insertions, 27 deletions
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);