/* Chrysalide - Outil d'analyse de fichiers binaires
* extract.c - organisation d'une extraction d'un élément d'une série interne
*
* 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 Foobar. If not, see .
*/
#include "extract.h"
#include
#include
#include "extract-int.h"
#include "../../../core/global.h"
/* --------------------- INTRODUCTION D'UNE NOUVELLE EXPRESSION --------------------- */
/* Initialise la classe des extractions d'éléments internes. */
static void g_scan_pending_extraction_class_init(GScanPendingExtractionClass *);
/* Initialise une instance d'extraction d'élément interne. */
static void g_scan_pending_extraction_init(GScanPendingExtraction *);
/* Supprime toutes les références externes. */
static void g_scan_pending_extraction_dispose(GScanPendingExtraction *);
/* Procède à la libération totale de la mémoire. */
static void g_scan_pending_extraction_finalize(GScanPendingExtraction *);
/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
/* Réduit une expression à une forme plus simple. */
static ScanReductionState g_scan_pending_extraction_reduce(const GScanPendingExtraction *, GScanContext *, GScanScope *, GScanExpression **);
/* Reproduit un accès en place dans une nouvelle instance. */
static void g_scan_pending_extraction_copy(GScanPendingExtraction *, const GScanPendingExtraction *);
/* ---------------------------------------------------------------------------------- */
/* INTRODUCTION D'UNE NOUVELLE EXPRESSION */
/* ---------------------------------------------------------------------------------- */
/* Indique le type défini pour une extraction d'élément de série interne. */
G_DEFINE_TYPE(GScanPendingExtraction, g_scan_pending_extraction, G_TYPE_SCAN_NAMED_ACCESS);
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des extractions d'éléments internes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_scan_pending_extraction_class_init(GScanPendingExtractionClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
GScanExpressionClass *expr; /* Version de classe parente */
GScanNamedAccessClass *access; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_pending_extraction_dispose;
object->finalize = (GObjectFinalizeFunc)g_scan_pending_extraction_finalize;
expr = G_SCAN_EXPRESSION_CLASS(klass);
expr->cmp_rich = (compare_expr_rich_fc)NULL;
expr->reduce = (reduce_expr_fc)g_scan_pending_extraction_reduce;
access = G_SCAN_NAMED_ACCESS_CLASS(klass);
access->copy = (copy_scan_access_fc)g_scan_pending_extraction_copy;
}
/******************************************************************************
* *
* Paramètres : extract = instance à initialiser. *
* *
* Description : Initialise une instance d'extraction d'élément interne. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_scan_pending_extraction_init(GScanPendingExtraction *extract)
{
extract->index = NULL;
}
/******************************************************************************
* *
* Paramètres : extract = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_scan_pending_extraction_dispose(GScanPendingExtraction *extract)
{
g_clear_object(&extract->index);
G_OBJECT_CLASS(g_scan_pending_extraction_parent_class)->dispose(G_OBJECT(extract));
}
/******************************************************************************
* *
* Paramètres : extract = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_scan_pending_extraction_finalize(GScanPendingExtraction *extract)
{
G_OBJECT_CLASS(g_scan_pending_extraction_parent_class)->finalize(G_OBJECT(extract));
}
/******************************************************************************
* *
* Paramètres : target = désignation de l'objet d'appel à identifier. *
* index = indice de l'élément à extraire. *
* *
* Description : Organise l'extraction d'un élément d'une série interne. *
* *
* Retour : Fonction mise en place. *
* *
* Remarques : - *
* *
******************************************************************************/
GScanExpression *g_scan_pending_extraction_new(const sized_string_t *target, GScanExpression *index)
{
GScanExpression *result; /* Structure à retourner */
result = g_object_new(G_TYPE_SCAN_PENDING_EXTRACTION, NULL);
if (!g_scan_pending_extraction_create(G_SCAN_PENDING_EXTRACTION(result), target, index))
g_clear_object(&result);
return result;
}
/******************************************************************************
* *
* Paramètres : extract = instance à initialiser pleinement. *
* target = désignation de l'objet d'appel à identifier. *
* index = indice de l'élément à extraire. *
* *
* Description : Met en place une expression d'extraction d'élément interne. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_scan_pending_extraction_create(GScanPendingExtraction *extract, const sized_string_t *target, GScanExpression *index)
{
bool result; /* Bilan à retourner */
result = g_scan_named_access_create(G_SCAN_NAMED_ACCESS(extract), target);
if (!result) goto exit;
extract->index = index;
g_object_ref(G_OBJECT(index));
exit:
return result;
}
/* ---------------------------------------------------------------------------------- */
/* IMPLEMENTATION DES FONCTIONS DE CLASSE */
/* ---------------------------------------------------------------------------------- */
/******************************************************************************
* *
* Paramètres : expr = expression à consulter. *
* ctx = contexte de suivi de l'analyse courante. *
* scope = portée courante des variables locales. *
* out = zone d'enregistrement de la réduction opérée. [OUT] *
* *
* Description : Réduit une expression à une forme plus simple. *
* *
* Retour : Bilan de l'opération : false en cas d'erreur irrécupérable. *
* *
* Remarques : - *
* *
******************************************************************************/
static ScanReductionState g_scan_pending_extraction_reduce(const GScanPendingExtraction *expr, GScanContext *ctx, GScanScope *scope, GScanExpression **out)
{
ScanReductionState result; /* Etat synthétisé à retourner */
GScanNamedAccess *access; /* Autre vision de l'expression*/
GScanRegisteredItem *resolved; /* Cible concrète obtenue */
GScanExpression *new; /* Nouvelle réduction obtenue */
GObject *final; /* Expression ou élément ? */
GScanExpression *new_next; /* Nouvelle version du suivant */
access = G_SCAN_NAMED_ACCESS(expr);
resolved = _g_scan_named_access_prepare_reduction(access, ctx, scope);
if (resolved == NULL)
result = SRS_UNRESOLVABLE;
else
{
/* Actualisation nécessaire des arguments ? */
result = g_scan_expression_reduce(expr->index, ctx, scope, &new);
/* Suite des traitements */
if (result == SRS_WAIT_FOR_SCAN)
{
/**
* Si changement il y a eu...
*/
if (new != expr->index)
{
*out = g_scan_pending_extraction_new(NULL, new);
/**
* Fonctionnement équivalent de :
* g_scan_named_access_set_base(G_SCAN_NAMED_ACCESS(*out), resolved);
*/
G_SCAN_NAMED_ACCESS(*out)->resolved = resolved;
g_object_ref(G_OBJECT(resolved));
if (G_SCAN_NAMED_ACCESS(expr)->next != NULL)
g_scan_named_access_attach_next(G_SCAN_NAMED_ACCESS(*out), G_SCAN_NAMED_ACCESS(expr)->next);
}
}
else if (result == SRS_REDUCED)
{
final = g_scan_registered_item_extract_at(resolved, new, ctx, scope);
if (final != NULL)
{
/**
* Si le produit de l'appel à la fonction est une expression d'évaluation
* classique, alors ce produit constitue la réduction finale de la chaîne.
*
* Ce cas de figure ne se rencontre normalement qu'en bout de chaîne.
*/
if (!G_IS_SCAN_REGISTERED_ITEM(final))
{
if (access->next != NULL)
result = SRS_UNRESOLVABLE;
else
{
*out = G_SCAN_EXPRESSION(final);
g_object_ref(G_OBJECT(final));
result = SRS_REDUCED;
}
}
else
{
if (access->next != NULL)
{
new_next = g_scan_named_access_duplicate(access->next, G_SCAN_REGISTERED_ITEM(final));
result = g_scan_expression_reduce(new_next, ctx, scope, out);
g_object_unref(G_OBJECT(new_next));
}
/**
* Le cas ci-après est typique de l'extension Kaitai : field[n]
* renvoie vers une instance GScanRegisteredItem (GKaitaiBrowser).
*
* Il n'y a donc pas d'expression en jeu, et l'élément est le dernier
* de la liste.
*/
else
{
if (g_scan_registered_item_reduce(G_SCAN_REGISTERED_ITEM(final), ctx, scope, out))
result = SRS_REDUCED;
else
result = SRS_UNRESOLVABLE;
}
}
}
else
result = SRS_UNRESOLVABLE;
g_clear_object(&final);
}
/* Libération locale des arguments reconstruits */
g_clear_object(&new);
g_object_unref(G_OBJECT(resolved));
}
return result;
}
/******************************************************************************
* *
* Paramètres : dest = emplacement d'enregistrement à constituer. [OUT] *
* src = expression source à copier. *
* *
* Description : Reproduit un accès en place dans une nouvelle instance. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_scan_pending_extraction_copy(GScanPendingExtraction *dest, const GScanPendingExtraction *src)
{
GScanNamedAccessClass *class; /* Classe parente à solliciter */
class = G_SCAN_NAMED_ACCESS_CLASS(g_scan_pending_extraction_parent_class);
class->copy(G_SCAN_NAMED_ACCESS(dest), G_SCAN_NAMED_ACCESS(src));
dest->index = src->index;
g_object_ref(G_OBJECT(src->index));
}