diff options
Diffstat (limited to 'src/decomp/expr/cond.c')
-rw-r--r-- | src/decomp/expr/cond.c | 287 |
1 files changed, 248 insertions, 39 deletions
diff --git a/src/decomp/expr/cond.c b/src/decomp/expr/cond.c index fab2c17..c776059 100644 --- a/src/decomp/expr/cond.c +++ b/src/decomp/expr/cond.c @@ -2,7 +2,7 @@ /* OpenIDA - Outil d'analyse de fichiers binaires * cond.c - représentation des conditions * - * Copyright (C) 2010 Cyrille Bagard + * Copyright (C) 2010-2013 Cyrille Bagard * * This file is part of OpenIDA. * @@ -24,6 +24,9 @@ #include "cond.h" +#include <malloc.h> + + #include "../expression-int.h" @@ -33,9 +36,17 @@ struct _GCondExpression { GDecExpression parent; /* A laisser en premier */ - GDecExpression *a; /* Premier élément à comparer */ - CompSignType sign; /* Méthode de comparaison */ - GDecExpression *b; /* Second élément à comparer */ + CondOperatorType operator; /* Opérateur de la liste */ + + union + { + GDecExpression *exp; /* Expression analysée de base */ + struct + { + GCondExpression **conds; /* Liste d'expressions */ + size_t count; /* Taille de cette liste */ + }; + }; }; @@ -64,6 +75,9 @@ static bool g_cond_expression_replace(GCondExpression *, GDecInstruction *, GDec /* Imprime pour l'écran un version humaine d'une expression. */ static GBufferLine *g_cond_expression_print(const GCondExpression *, GCodeBuffer *, GBufferLine *, GLangOutput *); +/* Réalise une négation sur une expression décompilée. */ +static bool g_cond_expression_negate(GCondExpression *); + /* Indique le type défini pour une condition binaire quelconque. */ @@ -90,7 +104,7 @@ static void g_cond_expression_class_init(GCondExpressionClass *klass) /****************************************************************************** * * -* Paramètres : expr = instance à initialiser. * +* Paramètres : cond = instance à initialiser. * * * * Description : Initialise une instance de condition binaire quelconque. * * * @@ -100,24 +114,29 @@ static void g_cond_expression_class_init(GCondExpressionClass *klass) * * ******************************************************************************/ -static void g_cond_expression_init(GCondExpression *expr) +static void g_cond_expression_init(GCondExpression *cond) { GDecInstruction *instr; /* Autre version de l'objet */ + GDecExpression *expr; /* Autre version de l'objet */ - instr = G_DEC_INSTRUCTION(expr); + instr = G_DEC_INSTRUCTION(cond); instr->visit = (dec_instr_visit_fc)g_cond_expression_visit; instr->replace = (dec_instr_replace_fc)g_cond_expression_replace; instr->print = (dec_instr_print_fc)g_cond_expression_print; + expr = G_DEC_EXPRESSION(cond); + + expr->negate = (dec_expr_negate_fc)g_cond_expression_negate; + + cond->operator = COT_NONE; + } /****************************************************************************** * * -* Paramètres : a = second élément à comparer. * -* sign = choix de la méthode de comparaison. * -* b = second élément à comparer. * +* Paramètres : exp = expression sur laquelle repose la condition. * * * * Description : Exprime une condition binaire quelconque. * * * @@ -127,17 +146,15 @@ static void g_cond_expression_init(GCondExpression *expr) * * ******************************************************************************/ -GDecInstruction *g_cond_expression_new(GDecExpression *a, CompSignType sign, GDecExpression *b) +GDecExpression *g_cond_expression_new(GDecExpression *exp) { GCondExpression *result; /* Expression à retourner */ result = g_object_new(G_TYPE_COND_EXPRESSION, NULL); - result->a = a; - result->sign = sign; - result->b = b; + result->exp = exp; - return G_DEC_INSTRUCTION(result); + return G_DEC_EXPRESSION(result); } @@ -160,14 +177,23 @@ GDecInstruction *g_cond_expression_new(GDecExpression *a, CompSignType sign, GDe static bool g_cond_expression_visit(GCondExpression *expr, dec_instr_visitor_cb callback, DecInstrVisitFlags flags, void *data) { bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ - result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->a), G_DEC_INSTRUCTION(expr), - callback, flags, data); - - if (result) - result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->b), G_DEC_INSTRUCTION(expr), + if (expr->operator == COT_NONE) + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->exp), G_DEC_INSTRUCTION(expr), callback, flags, data); + else + { + result = true; + + for (i = 0; i < expr->count && result; i++) + result = _g_dec_instruction_visit(G_DEC_INSTRUCTION(expr->conds[i]), + G_DEC_INSTRUCTION(expr), + callback, flags, data); + + } + return result; } @@ -190,30 +216,44 @@ static bool g_cond_expression_visit(GCondExpression *expr, dec_instr_visitor_cb static bool g_cond_expression_replace(GCondExpression *expr, GDecInstruction *old, GDecInstruction *new) { bool result; /* Bilan à retourner */ + size_t i; /* Boucle de parcours */ - if (expr->a == G_DEC_EXPRESSION(old)) + if (expr->operator == COT_NONE) { - g_object_unref(G_OBJECT(expr->a)); - g_object_ref(G_OBJECT(new)); - expr->a = G_DEC_EXPRESSION(new); + if (expr->exp == G_DEC_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->exp)); + g_object_ref(G_OBJECT(new)); + expr->exp = G_DEC_EXPRESSION(new); - result = true; + result = true; + + } + else + result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->exp), old, new); } else - result = g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->a), old, new); - - if (expr->b == G_DEC_EXPRESSION(old)) { - g_object_unref(G_OBJECT(expr->b)); - g_object_ref(G_OBJECT(new)); - expr->b = G_DEC_EXPRESSION(new); + result = false; - result = true; + for (i = 0; i < expr->count; i++) + { + if (expr->conds[i] == G_COND_EXPRESSION(old)) + { + g_object_unref(G_OBJECT(expr->conds[i])); + g_object_ref(G_OBJECT(new)); + expr->conds[i] = G_COND_EXPRESSION(new); + + result = true; + + } + else + result |= g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->conds[i]), old, new); + + } } - else - result |= g_dec_instruction_replace(G_DEC_INSTRUCTION(expr->b), old, new); return result; @@ -238,15 +278,184 @@ static bool g_cond_expression_replace(GCondExpression *expr, GDecInstruction *ol static GBufferLine *g_cond_expression_print(const GCondExpression *expr, GCodeBuffer *buffer, GBufferLine *line, GLangOutput *output) { GBufferLine *result; /* Ligne à retourner */ + size_t i; /* Boucle de parcours */ - result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->a), - buffer, line, output); + result = g_lang_output_encapsulate_condition(output, buffer, line, true); - g_lang_output_write_comp_sign(output, result, expr->sign); + if (expr->operator == COT_NONE) + result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->exp), + buffer, result, output); - result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->b), - buffer, result, output); + else + for (i = 0; i < expr->count; i++) + { + if (i > 0) + g_lang_output_write_cond_operator(output, result, expr->operator); + + result = g_dec_instruction_print(G_DEC_INSTRUCTION(expr->conds[i]), + buffer, result, output); + + } + + result = g_lang_output_encapsulate_condition(output, buffer, result, false); return result; } + + +/****************************************************************************** +* * +* Paramètres : cond = instance à traiter. * +* * +* Description : Réalise une négation sur une expression décompilée. * +* * +* Retour : true si la négation a été gérée, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +static bool g_cond_expression_negate(GCondExpression *cond) +{ + size_t i; /* Boucle de parcours */ + + if (cond->operator == COT_NONE) + g_dec_expression_negate(cond->exp); + + else + { + cond->operator = (cond->operator == COT_AND ? COT_OR : COT_AND); + + for (i = 0; i < cond->count; i++) + g_dec_expression_negate(G_DEC_EXPRESSION(cond->conds[i])); + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : cond = instance à consulter. * +* * +* Description : Fournit l'opération logique entre les comparaisons. * +* * +* Retour : Opération liant les différentes parties, ou COT_NONE. * +* * +* Remarques : - * +* * +******************************************************************************/ + +CondOperatorType g_cond_expression_get_operator(const GCondExpression *cond) +{ + return cond->operator; + +} + + +/****************************************************************************** +* * +* Paramètres : cond = instance à consulter. * +* * +* Description : Fournit l'expression d'une condition. * +* * +* Retour : Expression sur laquelle repose la condition. * +* * +* Remarques : - * +* * +******************************************************************************/ + +GDecExpression *g_cond_expression_get_expression(const GCondExpression *cond) +{ + return cond->exp; + +} + + +/****************************************************************************** +* * +* Paramètres : cond = instance à modifier. * +* exp = expression sur laquelle repose la condition. * +* * +* Description : Définit l'expression d'une condition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_cond_expression_set_expression(GCondExpression *cond, GDecExpression *exp) +{ + if (cond->exp != NULL) + g_object_unref(G_OBJECT(cond->exp)); + + cond->exp = exp; + +} + + +/****************************************************************************** +* * +* Paramètres : cond = instance à compléter. * +* extra = condition à rajouter. * +* op = lien avec le reste de la condition. * +* * +* Description : Etend l'expression d'une condition. * +* * +* Retour : - * +* * +* Remarques : - * +* * +******************************************************************************/ + +void g_cond_expression_add_condition(GCondExpression *cond, GCondExpression *extra, CondOperatorType op) +{ + GCondExpression *existing; /* Expr. première revalorisée */ + + if (cond->operator == COT_NONE) + { + existing = G_COND_EXPRESSION(g_cond_expression_new(cond->exp)); + goto gceac_replace_existing; + } + else + { + if (cond->operator == op) + { + cond->conds = (GCondExpression **)calloc(++cond->count, sizeof(GCondExpression)); + cond->conds[cond->count - 1] = extra; + } + else + { + existing = G_COND_EXPRESSION(g_cond_expression_new(NULL)); + + existing->operator = cond->operator; + existing->conds = cond->conds; + existing->count = cond->count; + + goto gceac_replace_existing; + + } + + } + + gceac_done: + + return; + + gceac_replace_existing: + + cond->operator = op; + + cond->conds = (GCondExpression **)calloc(2, sizeof(GCondExpression)); + cond->conds[0] = existing; + cond->conds[1] = extra; + + cond->count = 2; + + goto gceac_done; + +} |