/* Chrysalide - Outil d'analyse de fichiers binaires * bits.c - manipulation d'un champ de bits quelconque * * Copyright (C) 2015-2017 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 "bits.h" #include #include #include #include #include "asm.h" /* Champ de bits simple */ struct _bitfield_t { size_t length; /* Nombre de bits représentés */ size_t requested; /* Nombre de mots alloués */ unsigned long bits[0]; /* Mémoire d'accès associée */ }; /* Crée un champ de bits initialisé à zéro. */ static bitfield_t *_create_bit_field(size_t); /* Détermine si un ensemble de bits est homogène dans un champ. */ static bool test_state_in_bit_field(const bitfield_t *, size_t, size_t, bool); /****************************************************************************** * * * Paramètres : length = nom de bits du champ à représenter. * * * * Description : Crée un champ de bits initialisé à zéro. * * * * Retour : Champ de bits mis en place. * * * * Remarques : - * * * ******************************************************************************/ static bitfield_t *_create_bit_field(size_t length) { bitfield_t *result; /* Création à retourner */ size_t requested; /* Nombre de mots à allouer */ size_t base; /* Allocation de base en octets*/ requested = length / (sizeof(unsigned long) * 8); if (length % (sizeof(unsigned long) * 8) != 0) requested++; base = sizeof(bitfield_t) + requested * sizeof(unsigned long); result = (bitfield_t *)malloc(base); result->length = length; result->requested = requested; return result; } /****************************************************************************** * * * Paramètres : length = nombre de bits du champ à représenter. * * state = état initial de chaque des bits. * * * * Description : Crée un champ de bits initialisé. * * * * Retour : Champ de bits mis en place. * * * * Remarques : - * * * ******************************************************************************/ bitfield_t *create_bit_field(size_t length, bool state) { bitfield_t *result; /* Création à retourner */ result = _create_bit_field(length); if (state) set_all_in_bit_field(result); else reset_all_in_bit_field(result); return result; } /****************************************************************************** * * * Paramètres : field = champ de bits à dupliquer. * * * * Description : Crée une copie d'un champ de bits classique. * * * * Retour : Champ de bits mis en place. * * * * Remarques : - * * * ******************************************************************************/ bitfield_t *dup_bit_field(const bitfield_t *field) { bitfield_t *result; /* Copie à retourner */ result = _create_bit_field(field->length); memcpy(result->bits, field->bits, result->requested * sizeof(unsigned long)); return result; } /****************************************************************************** * * * Paramètres : field = champ de bits à effacer. * * * * Description : Supprime de la mémoire un champ de bits donné. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void delete_bit_field(bitfield_t *field) { free(field); } /****************************************************************************** * * * Paramètres : dest = champ de bits à modifier. * * src = champ de bits à utiliser pour l'opération. * * * * Description : Copie un champ de bits dans un autre. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void copy_bit_field(bitfield_t *dest, const bitfield_t *src) { assert(dest->length == src->length); memcpy(dest->bits, src->bits, dest->requested * sizeof(unsigned long)); } /****************************************************************************** * * * Paramètres : field = champ de bits à consulter. * * * * Description : Indique la taille d'un champ de bits donné. * * * * Retour : Taille du champ de bits. * * * * Remarques : - * * * ******************************************************************************/ size_t get_bit_field_size(const bitfield_t *field) { size_t result; /* Dimension à retourner */ result = field->length; return result; } /****************************************************************************** * * * Paramètres : a = premier champ à analyser. * * b = second champ à analyser. * * * * Description : Compare deux champs de bits entre eux. * * * * Retour : Bilan de la comparaison. * * * * Remarques : - * * * ******************************************************************************/ int compare_bit_fields(const bitfield_t *a, const bitfield_t *b) { int result; /* Bilan à retourner */ unsigned long final; /* Masque de la partie finale */ size_t i; /* Boucle de parcours */ unsigned long val_a; /* Valeur d'un mot de A */ unsigned long val_b; /* Valeur d'un mot de B */ result = 0; if (a->length > b->length) result = 1; else if (a->length < b->length) result = -1; if (result == 0) { final = a->length % sizeof(unsigned long); if (final == 0) final = ~0lu; else final = (1 << final) - 1; for (i = 0; i < a->requested && result == 0; i++) { val_a = a->bits[i]; val_b = b->bits[i]; if ((i + 1) == a->requested) { val_a &= final; val_b &= final; } if (val_a > val_b) result = 1; else if (val_a < val_b) result = -1; } } return result; } /****************************************************************************** * * * Paramètres : field = champ de bits à modifier. * * * * Description : Bascule à 0 un champ de bits dans son intégralité. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void reset_all_in_bit_field(bitfield_t *field) { memset(field->bits, 0u, field->requested * sizeof(unsigned long)); } /****************************************************************************** * * * Paramètres : field = champ de bits à modifier. * * * * Description : Bascule à 1 un champ de bits dans son intégralité. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void set_all_in_bit_field(bitfield_t *field) { memset(field->bits, ~0u, field->requested * sizeof(unsigned long)); } /****************************************************************************** * * * Paramètres : field = champ de bits à modifier. * * first = indice du premier bit à traiter. * * count = nombre de bits à marquer. * * * * Description : Bascule à 0 une partie d'un champ de bits. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void reset_in_bit_field(bitfield_t *field, size_t first, size_t count) { size_t last; /* Point d'arrêt de la boucle */ size_t i; /* Boucle de parcours */ size_t index; /* Cellule de tableau visée */ size_t remaining; /* Nombre de bits restants */ last = first + count; assert(last <= field->length); for (i = first; i < last; i++) { index = i / (sizeof(unsigned long) * 8); remaining = i % (sizeof(unsigned long) * 8); field->bits[index] &= ~(1ul << remaining); } } /****************************************************************************** * * * Paramètres : field = champ de bits à modifier. * * first = indice du premier bit à traiter. * * count = nombre de bits à marquer. * * * * Description : Bascule à 1 une partie d'un champ de bits. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void set_in_bit_field(bitfield_t *field, size_t first, size_t count) { size_t last; /* Point d'arrêt de la boucle */ size_t i; /* Boucle de parcours */ size_t index; /* Cellule de tableau visée */ size_t remaining; /* Nombre de bits restants */ last = first + count; assert(last <= field->length); for (i = first; i < last; i++) { index = i / (sizeof(unsigned long) * 8); remaining = i % (sizeof(unsigned long) * 8); field->bits[index] |= (1ul << remaining); } } /****************************************************************************** * * * Paramètres : dest = champ de bits à modifier. * * src = champ de bits à utiliser pour l'opération. * * * * Description : Réalise une opération ET logique entre deux champs de bits. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void and_bit_field(bitfield_t *dest, const bitfield_t *src) { size_t i; /* Boucle de parcours */ assert(dest->length == src->length); for (i = 0; i < dest->requested; i++) dest->bits[i] &= src->bits[i]; } /****************************************************************************** * * * Paramètres : dest = champ de bits à modifier. * * src = champ de bits à utiliser pour l'opération. * * * * Description : Réalise une opération OU logique entre deux champs de bits. * * * * Retour : - * * * * Remarques : - * * * ******************************************************************************/ void or_bit_field(bitfield_t *dest, const bitfield_t *src) { size_t i; /* Boucle de parcours */ assert(dest->length == src->length); for (i = 0; i < dest->requested; i++) dest->bits[i] |= src->bits[i]; } /****************************************************************************** * * * Paramètres : field = champ de bits à consulter. * * n = indice du bit à traiter. * * * * Description : Détermine si un bit est à 1 dans un champ de bits. * * * * Retour : true si le bit correspondant est à l'état haut. * * * * Remarques : - * * * ******************************************************************************/ bool test_in_bit_field(const bitfield_t *field, size_t n) { bool result; /* Valeur retrouvée à renvoyer */ size_t index; /* Cellule de tableau visée */ size_t remaining; /* Nombre de bits restants */ assert(n < field->length); index = n / (sizeof(unsigned long) * 8); remaining = n % (sizeof(unsigned long) * 8); result = field->bits[index] & (1ul << remaining); return result; } /****************************************************************************** * * * Paramètres : field = champ de bits à modifier. * * first = indice du premier bit à traiter. * * count = nombre de bits à marquer. * * state = état global à retrouver idéalement. * * * * Description : Détermine si un ensemble de bits est homogène dans un champ. * * * * Retour : true si les bits correspondants sont à l'état indiqué. * * * * Remarques : - * * * ******************************************************************************/ static bool test_state_in_bit_field(const bitfield_t *field, size_t first, size_t count, bool state) { size_t last; /* Point d'arrêt de la boucle */ size_t i; /* Boucle de parcours */ size_t index; /* Cellule de tableau visée */ size_t remaining; /* Nombre de bits restants */ bool current; /* Etat d'un bit donné */ assert(count > 0); last = first + count; for (i = first; i < last; i++) { index = i / (sizeof(unsigned long) * 8); remaining = i % (sizeof(unsigned long) * 8); current = field->bits[index] & (1ul << remaining); if (current != state) break; } return (i == last); } /****************************************************************************** * * * Paramètres : field = champ de bits à consulter. * * first = indice du premier bit à traiter. * * count = nombre de bits à analyser. * * * * Description : Détermine si un ensemble de bits est à 0 dans un champ. * * * * Retour : true si les bits correspondants sont à l'état bas. * * * * Remarques : - * * * ******************************************************************************/ bool test_none_in_bit_field(const bitfield_t *field, size_t first, size_t count) { bool result; /* Valeur retrouvée à renvoyer */ result = test_state_in_bit_field(field, first, count, false); return result; } /****************************************************************************** * * * Paramètres : field = champ de bits à consulter. * * first = indice du premier bit à traiter. * * count = nombre de bits à analyser. * * * * Description : Détermine si un ensemble de bits est à 1 dans un champ. * * * * Retour : true si les bits correspondants sont à l'état haut. * * * * Remarques : - * * * ******************************************************************************/ bool test_all_in_bit_field(const bitfield_t *field, size_t first, size_t count) { bool result; /* Valeur retrouvée à renvoyer */ result = test_state_in_bit_field(field, first, count, true); return result; } /****************************************************************************** * * * Paramètres : field = champ de bits à consulter. * * * * Description : Détermine le nombre de bits à 1 dans un champ. * * * * Retour : Valeur positive ou nulle. * * * * Remarques : - * * * ******************************************************************************/ size_t popcount_for_bit_field(const bitfield_t *field) { size_t result; /* Quantité à renvoyer */ size_t remaining; /* Nombre de bits restants */ size_t i; /* Boucle de parcours */ unsigned long value; /* Valeur masquée à traiter */ result = 0; remaining = field->length; for (i = 0; i < field->requested; i++) { value = field->bits[i]; if (remaining < (8 * sizeof(unsigned long))) value &= (1lu << (remaining + 1)) - 1; #if __WORDSIZE == 64 result += popcount_64(value); #elif __WORDSIZE == 32 result += popcount_32(value); #else # error "Unkown word size" #endif remaining -= 8 * sizeof(unsigned long); } return result; }