/* Chrysalide - Outil d'analyse de fichiers binaires
* array.c - données associées à un flux de données 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 .
*/
#include "array.h"
#include
#include
#include
#include
#include "array-int.h"
#include "expression.h"
/* Initialise la classe des flux de données pour Kaitai. */
static void g_kaitai_array_class_init(GKaitaiArrayClass *);
/* Initialise un flux de données accessibles à Kaitai. */
static void g_kaitai_array_init(GKaitaiArray *);
/* Supprime toutes les références externes. */
static void g_kaitai_array_dispose(GKaitaiArray *);
/* Procède à la libération totale de la mémoire. */
static void g_kaitai_array_finalize(GKaitaiArray *);
/* Détermine la taille de la séquence d'octets du tableau. */
static bool g_kaitai_array_compute_bytes_length(const GKaitaiArray *, size_t *);
/* Indique le type défini pour un tableau rassemblant des éléments Kaitai. */
G_DEFINE_TYPE(GKaitaiArray, g_kaitai_array, G_TYPE_OBJECT);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des tableau d'éléments Kaitai. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_kaitai_array_class_init(GKaitaiArrayClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_kaitai_array_dispose;
object->finalize = (GObjectFinalizeFunc)g_kaitai_array_finalize;
}
/******************************************************************************
* *
* Paramètres : array = instance à initialiser. *
* *
* Description : Initialise un tableau rassemblant des éléments divers. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_kaitai_array_init(GKaitaiArray *array)
{
array->items = NULL;
array->count = 0;
}
/******************************************************************************
* *
* Paramètres : array = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_kaitai_array_dispose(GKaitaiArray *array)
{
G_OBJECT_CLASS(g_kaitai_array_parent_class)->dispose(G_OBJECT(array));
}
/******************************************************************************
* *
* Paramètres : array = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_kaitai_array_finalize(GKaitaiArray *array)
{
G_OBJECT_CLASS(g_kaitai_array_parent_class)->finalize(G_OBJECT(array));
}
/******************************************************************************
* *
* Paramètres : - *
* *
* Description : Constitue une amorce de tableau pour rassembler des éléments.*
* *
* Retour : Instance mise en place ou NULL en cas d'échec. *
* *
* Remarques : - *
* *
******************************************************************************/
GKaitaiArray *g_kaitai_array_new(void)
{
GKaitaiArray *result; /* Structure à retourner */
result = g_object_new(G_TYPE_KAITAI_ARRAY, NULL);
return result;
}
/******************************************************************************
* *
* Paramètres : array = tableau Kaitai à consulter. *
* *
* Description : Dénombre le nombre d'éléments enregistrés. *
* *
* Retour : Taille du tableau manipulé. *
* *
* Remarques : - *
* *
******************************************************************************/
size_t g_kaitai_array_count_items(const GKaitaiArray *array)
{
size_t result; /* Quantité à retourner */
result = array->count;
return result;
}
/******************************************************************************
* *
* Paramètres : array = tableau Kaitai à compléter. *
* item = élément Kaitai à archiver. *
* *
* Description : Intègre un élément supplémentaire dans un tableau Kaitai. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_kaitai_array_append_item(GKaitaiArray *array, const resolved_value_t *item)
{
array->items = realloc(array->items, ++array->count * sizeof(resolved_value_t));
COPY_RESOLVED_VALUE(array->items[array->count - 1], *item);
}
/******************************************************************************
* *
* Paramètres : list = ensemble de correspondances attribut/binaire. *
* index = indice de la correspondance visée. *
* item = élément archivé dans le talbeau à fournir. [OUT] *
* *
* Description : Fournit un élément ciblé dans un tableau Kaitai. *
* *
* Retour : Validité de l'emplacmeent pour élément à renseigner. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_kaitai_array_get_item(const GKaitaiArray *array, size_t index, resolved_value_t *item)
{
bool result; /* Bilan à retourner */
result = (index < array->count);
if (result)
COPY_RESOLVED_VALUE(*item, array->items[index]);
return result;
}
/******************************************************************************
* *
* Paramètres : array = tableau Kaitai à consulter. *
* length = nombre d'octets représentés. [OUT] *
* *
* Description : Détermine la taille de la séquence d'octets du tableau. *
* *
* Retour : true si le tableau peut être converti en octets, ou false. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_kaitai_array_compute_bytes_length(const GKaitaiArray *array, size_t *length)
{
bool result; /* Bilan à retourner */
size_t i; /* Boucle de parcours */
const resolved_value_t *item; /* Elément en cours d'analyse */
size_t extra; /* Taille d'un sous-tableau */
result = true;
*length = 0;
for (i = 0; i < array->count && result; i++)
{
item = &array->items[i];
switch (item->type)
{
case GVT_UNSIGNED_INTEGER:
result = (item->unsigned_integer <= UCHAR_MAX);
if (result) (*length)++;
break;
case GVT_SIGNED_INTEGER:
result = (0 <= item->signed_integer && item->signed_integer <= SCHAR_MAX);
if (result) (*length)++;
break;
case GVT_BYTES:
*length += item->bytes.len;
break;
case GVT_ARRAY:
result = g_kaitai_array_compute_bytes_length(item->array, &extra);
if (result) *length += extra;
break;
default:
result = false;
break;
}
}
return result;
}
/******************************************************************************
* *
* Paramètres : array = tableau Kaitai à consulter. *
* bytes = conversion en série d'octets équivalent. [OUT] *
* *
* Description : Convertit un tableau d'éléments en séquence d'octets. *
* *
* Retour : true si une série d'octets a pu être constituée, ou false. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_kaitai_array_convert_to_bytes(const GKaitaiArray *array, sized_string_t *bytes)
{
bool result; /* Bilan à retourner */
size_t length; /* Taille de la chaîne finale */
size_t i; /* Boucle de parcours */
const resolved_value_t *item; /* Elément en cours d'analyse */
char *iter; /* Tête d'écriture */
sized_string_t extra; /* Données d'un sous-tableau */
/* Détermination de la taille finale */
result = g_kaitai_array_compute_bytes_length(array, &length);
/* Construction d'une chaîne d'octets si possible */
if (result)
{
bytes->data = malloc(length * sizeof(char));
bytes->len = length;
iter = bytes->data;
for (i = 0; i < array->count; i++)
{
item = &array->items[i];
switch (item->type)
{
case GVT_UNSIGNED_INTEGER:
*iter = item->unsigned_integer;
iter++;
break;
case GVT_SIGNED_INTEGER:
*iter = item->signed_integer;
iter++;
break;
case GVT_BYTES:
memcpy(iter, item->bytes.data, item->bytes.len);
iter += item->bytes.len;
break;
case GVT_ARRAY:
result = g_kaitai_array_convert_to_bytes(item->array, &extra);
assert(result);
memcpy(iter, extra.data, extra.len);
iter += extra.len;
exit_szstr(&extra);
break;
default:
break;
}
}
}
return result;
}