diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2023-10-09 22:49:59 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2023-10-09 22:49:59 (GMT) |
commit | 7c6fe94c90d320813d0d78a9dbef707696f31505 (patch) | |
tree | 912b5c51469c02e6ef680c0c60739787ccff4891 /plugins/kaitai/parsers | |
parent | cb05b99a8c451ff80d88f988e2654c794b0f3750 (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.h | 3 | ||||
-rw-r--r-- | plugins/kaitai/parsers/attribute.c | 206 | ||||
-rw-r--r-- | plugins/kaitai/parsers/attribute.h | 20 | ||||
-rw-r--r-- | plugins/kaitai/parsers/instance.c | 149 | ||||
-rw-r--r-- | plugins/kaitai/parsers/instance.h | 3 | ||||
-rw-r--r-- | plugins/kaitai/parsers/struct.c | 45 | ||||
-rw-r--r-- | plugins/kaitai/parsers/switch.c | 112 |
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; } |