/* Chrysalide - Outil d'analyse de fichiers binaires * offset.c - décomposition d'un motif de recherche en atomes assemblés * * 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 "offset.h" #include /****************************************************************************** * * * Paramètres : range = bornes décrivant un espace quelconque. * * available = espace restant disponible. * * min = point de départ pour parcourir une zone. [OUT] * * max = point d'arrivée pour parcourir une zone. [OUT] * * * * Description : Fournit les bornes d'une zone à analyser. * * * * Retour : true si assez d'espace est disponible, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool get_node_offset_range(const node_offset_range_t *range, phys_t len, phys_t available, phys_t *min, phys_t *max) { bool result; /* Bilan à retourner */ if ((len + range->min) > available) result = false; else { result = true; *min = range->min; *max = range->max; if ((len + *max) > available) { *max = available - len; assert(*max >= *min); } } return result; } /****************************************************************************** * * * Paramètres : offset = suivi de tolérances bornées à initialiser. * * * * Description : Initialise une mémorisation d'intervales de tolérance. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void init_node_search_offset(node_search_offset_t *offset) { offset->ranges = NULL; offset->allocated = 0; offset->gen_ptr = NULL; offset->used = 0; } /****************************************************************************** * * * Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] * * src = suivi de tolérances bornées à copier. * * * * Description : Copie une mémorisation d'intervales entre positions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void copy_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src) { init_node_search_offset(dest); switch (src->used) { case 0: dest->gen_ptr = NULL; break; case 1: dest->range = src->range; dest->gen_ptr = &dest->range; break; default: dest->ranges = malloc(src->used * sizeof(node_offset_range_t)); memcpy(dest->ranges, src->ranges, src->used * sizeof(node_offset_range_t)); dest->gen_ptr = dest->ranges;; break; } dest->used = src->used; } /****************************************************************************** * * * Paramètres : dest = suivi de tolérances bornées à initialiser. [OUT] * * src = suivi de tolérances bornées à copier. * * * * Description : Fusionne une mémorisation d'intervales entre positions. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void merge_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src) { node_offset_range_t * const *list; /* Liste d'intervales à copier */ size_t i; /* Boucle de parcours */ if ((dest->used + src->used) > 1 && (dest->used + src->used) > dest->allocated) { dest->allocated += src->used; dest->ranges = realloc(dest->ranges, dest->allocated * sizeof(node_offset_range_t)); } list = get_node_search_offset_ranges(src, (size_t []){ 0 }); for (i = 0; i < src->used; i++) add_range_to_node_search_offset(dest, (*list)[i].min, (*list)[i].max, NULL); } /****************************************************************************** * * * Paramètres : offset = suivi de tolérances bornées à terminer. * * * * Description : Met fin à une mémorisation d'intervales de tolérance. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void exit_node_search_offset(node_search_offset_t *offset) { if (offset->ranges != NULL) free(offset->ranges); } /****************************************************************************** * * * Paramètres : offset = suivi de tolérances bornées à consulter. * * count = nombre de bornes enregistrées. [OUT] * * * * Description : Fournit la liste des tolérances bornées établies à présent. * * * * Retour : Liste d'intervales en lecture seule. * * * * Remarques : - * * * ******************************************************************************/ node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *offset, size_t *count) { node_offset_range_t * const *result; /* Série à renvoyer */ result = &offset->gen_ptr; *count = offset->used; return result; } /****************************************************************************** * * * Paramètres : offset = suivi de tolérances bornées à consulter. * * count = nombre de bornes enregistrées. [OUT] * * * * Description : Fournit la liste des tolérances bornées établies à présent. * * * * Retour : Liste d'intervales en lecture seule. * * * * Remarques : - * * * ******************************************************************************/ const node_offset_range_t * const get_node_search_offset_ranges_2(const node_search_offset_t *offset, size_t *count) { node_offset_range_t *result; /* Série à renvoyer */ result = offset->gen_ptr; *count = offset->used; return result; } /****************************************************************************** * * * Paramètres : offset = suivi de tolérances bornées à consulter. * * min = point de départ pour parcourir une zone. * * max = point d'arrivée pour parcourir une zone. * * datasize = taille maximale pour définir une inversion NOT. * * * * Description : Ajoute un nouvel espace borné aux décalages tolérés. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void add_range_to_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, const phys_t *datasize) { bool not; /* Traduction de la taille */ size_t needed; /* Nombre d'emplacements requis*/ not = (datasize != NULL); /* Si le réceptacle unique peut être employé... */ if (offset->used == 0 && !not) { offset->range.min = min; offset->range.max = max; offset->used = 1; offset->gen_ptr = &offset->range; } /* Sinon le groupe dynamique est sollicité */ else { needed = offset->used + (not ? 2 : 1); if (needed > offset->allocated) { offset->ranges = realloc(offset->ranges, needed * sizeof(node_offset_range_t)); offset->allocated = needed; } /* Bascule d'un éventuel intervale courant */ if (offset->used == 1) { offset->ranges[0].min = offset->range.min; offset->ranges[0].max = offset->range.max; } if (not) { if (min > 0) { offset->ranges[offset->used].min = 0; offset->ranges[offset->used].max = min - 1; offset->used++; } if ((max + 1) < *datasize) { offset->ranges[offset->used].min = max + 1; offset->ranges[offset->used].max = *datasize - (max + 1); offset->used++; } } else { offset->ranges[offset->used].min = min; offset->ranges[offset->used].max = max; offset->used++; } offset->gen_ptr = offset->ranges; } } /****************************************************************************** * * * Paramètres : offset = suivi de tolérances bornées à consulter. * * min = point de départ pour parcourir une zone. * * max = point d'arrivée pour parcourir une zone. * * has_max = validité de la valeur maximale transmise. * * * * Description : Etend les décalages tolérés avec un nouvel espace. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void extend_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, bool has_max) { size_t i; /* Boucle de parcours */ switch (offset->used) { /* Si le réceptacle unique peut être employé... */ case 0: offset->range.min = min; offset->range.max = max; offset->range.has_max = has_max; offset->used = 1; offset->gen_ptr = &offset->range; break; /* Si un espace unique est enregistré */ case 1: offset->range.min += min; offset->range.max += max; offset->range.has_max &= has_max; break; /* Sinon le groupe dynamique est sollicité */ default: for (i = 0; i < offset->used; i++) { offset->ranges[i].min += min; offset->ranges[i].max += max; offset->ranges[i].has_max &= has_max; } break; } } /****************************************************************************** * * * Paramètres : offset = suivi de tolérances bornées à consulter. * * last = dernière position validée. * * pos = nouvelle position potentielle. * * * * Description : Indique si une position est comprise dans un intervale. * * * * Retour : Bilan de la détermination. * * * * Remarques : - * * * ******************************************************************************/ bool does_node_search_offset_include_pos_forward(const node_search_offset_t *offset, phys_t last, phys_t pos) { bool result; /* Bilan à retourner */ size_t i; /* Boucle de parcours */ const node_offset_range_t *range; /* Accès rapide aux infos. */ result = false; for (i = 0; i < offset->used; i++) { range = &offset->gen_ptr[i]; result = ((last + range->min) <= pos && pos <= (last + range->max)); if (result) break; } return result; }