diff options
Diffstat (limited to 'src/common/io.c')
-rw-r--r-- | src/common/io.c | 851 |
1 files changed, 850 insertions, 1 deletions
diff --git a/src/common/io.c b/src/common/io.c index 3208a2a..f325e7d 100644 --- a/src/common/io.c +++ b/src/common/io.c @@ -1,6 +1,6 @@ /* Chrysalide - Outil d'analyse de fichiers binaires - * io.c - entrées sorties fiables + * io.c - entrées sorties fiables et manipulation des nombres * * Copyright (C) 2014-2019 Cyrille Bagard * @@ -24,8 +24,10 @@ #include "io.h" +#include <assert.h> #include <errno.h> #include <malloc.h> +#include <stdarg.h> #include <stdint.h> #include <string.h> #include <unistd.h> @@ -37,6 +39,24 @@ +/** + * Mutualisation des aiguillages... + */ + +#if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN + + /* __PDP_ENDIAN et Cie... */ +# error "Congratulations! Your byte order is not supported!" + +#endif + + + +/* ---------------------------------------------------------------------------------- */ +/* ENTREES/SORTIES BRUTES ENCADREES */ +/* ---------------------------------------------------------------------------------- */ + + /****************************************************************************** * * * Paramètres : fd = flux ouvert en lecture. * @@ -284,3 +304,832 @@ bool safe_send(int sockfd, const void *buf, size_t len, int flags) return (remaining == 0); } + + + +/* ---------------------------------------------------------------------------------- */ +/* CONVERSION ENTRE BOUTISMES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : value = valeur d'origine à manipuler. * +* endian = ordre des bits dans la source. * +* * +* Description : Adapte un nombre sur 16 bits à un boutisme donné. * +* * +* Retour : Valeur transformée au besoin. * +* * +* Remarques : - * +* * +******************************************************************************/ + +uint16_t swap_u16(const uint16_t *value, SourceEndian endian) +{ + uint16_t result; /* Valeur à retourner */ + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + result = *value; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0; + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + result = *value; + +#endif + + break; + + default: + assert(false); + result = -1; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : value = valeur d'origine à manipuler. * +* endian = ordre des bits dans la source. * +* * +* Description : Adapte un nombre sur 16 bits à un boutisme donné. * +* * +* Retour : Valeur transformée au besoin. * +* * +* Remarques : - * +* * +******************************************************************************/ + +uint32_t swap_u32(const uint32_t *value, SourceEndian endian) +{ + uint32_t result; /* Valeur à retourner */ + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + result = *value; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + result = ((*value >> 0) & 0xff) << 24 | ((*value >> 8) & 0xff) << 16 + | ((*value >> 16) & 0xff) << 8 | ((*value >> 24) & 0xff) << 0; + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + result = ((*value >> 0) & 0xff) << 24 | ((*value >> 8) & 0xff) << 16 + | ((*value >> 16) & 0xff) << 8 | ((*value >> 24) & 0xff) << 0; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + result = *value; + +#endif + + break; + + default: + assert(false); + result = -1; + break; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : value = valeur d'origine à manipuler. * +* endian = ordre des bits dans la source. * +* * +* Description : Adapte un nombre sur 16 bits à un boutisme donné. * +* * +* Retour : Valeur transformée au besoin. * +* * +* Remarques : - * +* * +******************************************************************************/ + +uint64_t swap_u64(const uint64_t *value, SourceEndian endian) +{ + uint64_t result; /* Valeur à retourner */ + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + result = *value; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + result = ((*value >> 0) & 0xff) << 56 | ((*value >> 8) & 0xff) << 48 + | ((*value >> 16) & 0xff) << 40 | ((*value >> 24) & 0xff) << 32 + | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16 + | ((*value >> 48) & 0xff) << 8 | ((*value >> 56) & 0xff) << 0; + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + result = ((*value >> 0) & 0xff) << 56 | ((*value >> 8) & 0xff) << 48 + | ((*value >> 16) & 0xff) << 40 | ((*value >> 24) & 0xff) << 32 + | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16 + | ((*value >> 48) & 0xff) << 8 | ((*value >> 56) & 0xff) << 0; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + result = *value; + +#endif + + break; + + default: + assert(false); + result = -1; + break; + + } + + return result; + +} + + + +/* ---------------------------------------------------------------------------------- */ +/* BOUTISME DES ENTREES / SORTIES */ +/* ---------------------------------------------------------------------------------- */ + + +/****************************************************************************** +* * +* Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* low = position éventuelle des 4 bits visés. [OUT] * +* * +* Description : Lit un nombre non signé sur 4 bits. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_u4(uint8_t *target, const bin_t *data, phys_t *pos, phys_t end, bool *low) +{ + if (end < 1) return false; + if (*pos > (end - 1)) return false; + + if (*low) + { + *target = data[*pos] & 0x0f; + *low = false; + } + else + { + *target = (data[*pos] & 0xf0) >> 4; + *low = true; + *pos += 1; + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* * +* Description : Lit un nombre non signé sur un octet. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_u8(uint8_t *target, const bin_t *data, phys_t *pos, phys_t end) +{ + if (end < 1) return false; + if (*pos > (end - 1)) return false; + + *target = data[*pos]; + + *pos += 1; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* endian = ordre des bits dans la source. * +* * +* Description : Lit un nombre non signé sur deux octets. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_u16(uint16_t *target, const bin_t *data, phys_t *pos, phys_t end, SourceEndian endian) +{ + if (end < 2) return false; + if (*pos > (end - 2)) return false; + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos] | (uint16_t)data[*pos + 1] << 8; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos + 1] | (uint16_t)data[*pos] << 8; + +#endif + + break; + + case SRE_LITTLE_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos] << 8 | (uint16_t)data[*pos + 1]; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos + 1] << 8 | (uint16_t)data[*pos]; + +#endif + + break; + + case SRE_BIG_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos + 1] << 8 | (uint16_t)data[*pos]; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos] << 8 | (uint16_t)data[*pos + 1]; + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos + 1] | (uint16_t)data[*pos] << 8; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos] | (uint16_t)data[*pos + 1] << 8; + +#endif + + break; + + default: + return false; + break; + + } + + *pos += 2; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* endian = ordre des bits dans la source. * +* * +* Description : Lit un nombre non signé sur quatre octets. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_u32(uint32_t *target, const bin_t *data, phys_t *pos, phys_t end, SourceEndian endian) +{ + if (end < 4) return false; + if (*pos > (end - 4)) return false; + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos] | (uint32_t)data[*pos + 1] << 8; + *target |= data[*pos + 2] << 16 | (uint32_t)data[*pos + 3] << 24; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos + 3] | (uint32_t)data[*pos + 2] << 8; + *target |= data[*pos + 1] << 16 | (uint32_t)data[*pos] << 24; + +#endif + + break; + + case SRE_LITTLE_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos] << 8 | (uint32_t)data[*pos + 1]; + *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2]; + *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16; + +#endif + + break; + + case SRE_BIG_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2]; + *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos] << 8 | (uint32_t)data[*pos + 1]; + *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16; + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = data[*pos + 3] | (uint32_t)data[*pos + 2] << 8; + *target |= data[*pos + 1] << 16 | (uint32_t)data[*pos] << 24; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = data[*pos] | (uint32_t)data[*pos + 1] << 8; + *target |= data[*pos + 2] << 16 | (uint32_t)data[*pos + 3] << 24; + +#endif + + break; + + default: + return false; + break; + + } + + *pos += 4; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* endian = ordre des bits dans la source. * +* * +* Description : Lit un nombre non signé sur huit octets. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool read_u64(uint64_t *target, const bin_t *data, phys_t *pos, phys_t end, SourceEndian endian) +{ + if (end < 8) return false; + if (*pos > (end - 8)) return false; + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = (uint64_t)data[*pos] | (uint64_t)data[*pos + 1] << 8; + *target |= (uint64_t)data[*pos + 2] << 16 | (uint64_t)data[*pos + 3] << 24; + *target |= (uint64_t)data[*pos + 4] << 32 | (uint64_t)data[*pos + 5] << 40; + *target |= (uint64_t)data[*pos + 6] << 48 | (uint64_t)data[*pos + 7] << 56; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = (uint64_t)data[*pos + 7] | (uint64_t)data[*pos + 6] << 8; + *target |= (uint64_t)data[*pos + 5] << 16 | (uint64_t)data[*pos + 4] << 24; + *target |= (uint64_t)data[*pos + 3] << 32 | (uint64_t)data[*pos + 2] << 40; + *target |= (uint64_t)data[*pos + 1] << 48 | (uint64_t)data[*pos] << 56; + +#endif + + break; + + case SRE_LITTLE_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = (uint64_t)data[*pos] << 8 | (uint64_t)data[*pos + 1]; + *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16; + *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32; + *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6]; + *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16; + *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32; + *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48; + +#endif + + break; + + case SRE_BIG_WORD: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6]; + *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16; + *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32; + *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = (uint64_t)data[*pos] << 8| (uint64_t)data[*pos + 1]; + *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16; + *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32; + *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48; + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target = (uint64_t)data[*pos + 7] | (uint64_t)data[*pos + 6] << 8; + *target |= (uint64_t)data[*pos + 5] << 16 | (uint64_t)data[*pos + 4] << 24; + *target |= (uint64_t)data[*pos + 3] << 32 | (uint64_t)data[*pos + 2] << 40; + *target |= (uint64_t)data[*pos + 1] << 48 | (uint64_t)data[*pos] << 56; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target = (uint64_t)data[*pos] | (uint64_t)data[*pos + 1] << 8; + *target |= (uint64_t)data[*pos + 2] << 16 | (uint64_t)data[*pos + 3] << 24; + *target |= (uint64_t)data[*pos + 4] << 32 | (uint64_t)data[*pos + 5] << 40; + *target |= (uint64_t)data[*pos + 6] << 48 | (uint64_t)data[*pos + 7] << 56; + +#endif + + break; + + default: + return false; + break; + + } + + *pos += 8; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : value = source de la valeur à transcrire. * +* size = taille de cette source de données. * +* data = flux de données à modifier. [OUT] * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* endian = ordre des bits dans la source. * +* * +* Description : Ecrit un nombre non signé sur n octets. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool _write_un(const bin_t *value, size_t size, bin_t *data, off_t *pos, off_t end, SourceEndian endian) +{ + size_t i; /* Boucle de parcours */ + + if (end < size) return false; + if (*pos > (end - size)) return false; + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + memcpy(&data[*pos], value, size); + (*pos) += size; + +#elif __BYTE_ORDER == __BIG_ENDIAN + + for (i = 0; i < size; i++, (*pos)++) + *(data + *pos) = *(value + size - i - 1); + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + for (i = 0; i < size; i++, (*pos)++) + *(data + *pos) = *(value + size - i - 1); + +#elif __BYTE_ORDER == __BIG_ENDIAN + + memcpy(&data[*pos], value, size); + (*pos) += size; + +#endif + + break; + + default: + return false; + break; + + } + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* endian = ordre des bits dans la source. * +* * +* Description : Lit un nombre hexadécimal non signé sur deux octets. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool strtou8(uint8_t *target, const char *data, size_t *pos, size_t end, SourceEndian endian) +{ + size_t i; /* Boucle de parcours */ + + if (end < 2) return false; + if (*pos > (end - 2)) return false; + + *target = 0; + + for (i = 0; i < 2; i++) + switch (data[*pos + i]) + { + case '0' ... '9': + *target |= ((data[*pos + i] - '0') << (4 * (1 - i))); + break; + + case 'A' ... 'F': + *target |= ((data[*pos + i] + 10 - 'A') << (4 * (1 - i))); + break; + + case 'a' ... 'f': + *target |= ((data[*pos + i] + 10 - 'a') << (4 * (1 - i))); + break; + + } + + *pos += 2; + + return true; + +} + + +/****************************************************************************** +* * +* Paramètres : n = nombre d'octets constituant le nombre à lire. * +* data = flux de données à analyser. * +* pos = position courante dans ce flux. [OUT] * +* end = limite des données à analyser. * +* endian = ordre des bits dans la source. * +* ... = lieu d'enregistrement de la lecture. [OUT] * +* * +* Description : Lit un nombre hexadécimal non signé sur n octets. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool _strtoun(uint8_t n, const char *data, size_t *pos, size_t end, SourceEndian endian, ...) +{ + bool result; /* Bilan à renvoyer */ + va_list ap; /* Arguments variables */ + uint8_t *target8; /* Enregistrement sur 8 bits */ + uint16_t *target16; /* Enregistrement sur 16 bits */ + uint32_t *target32; /* Enregistrement sur 32 bits */ + uint64_t *target64; /* Enregistrement sur 64 bits */ + uint8_t i; /* Boucle de parcours #1 */ + size_t j; /* Boucle de parcours #2 */ + uint8_t tmp; /* Valeur temporaire de 8 bits */ + + if (end < (n * 2)) return false; + if (*pos > (end - (n * 2))) return false; + + /* Récupération de la destination */ + + va_start(ap, endian); + + switch (n) + { + case 1: + target8 = va_arg(ap, uint8_t *); + *target8 = 0; + target64 = (uint64_t *)target8; + break; + case 2: + target16 = va_arg(ap, uint16_t *); + *target16 = 0; + target64 = (uint64_t *)target16; + break; + case 4: + target32 = va_arg(ap, uint32_t *); + *target32 = 0; + target64 = (uint64_t *)target32; + break; + case 8: + target64 = va_arg(ap, uint64_t *); + *target64 = 0ull; + break; + default: + va_end(ap); + return false; + break; + } + + va_end(ap); + + /* Lecture des données */ + + result = true; + + for (i = 0; i < n && result; i++) + { + tmp = 0; + + for (j = 0; j < 2 && result; j++) + switch (data[*pos + j]) + { + case '0' ... '9': + tmp |= ((data[*pos + j] - '0') << (4 * (1 - j))); + break; + + case 'A' ... 'F': + tmp |= ((data[*pos + j] + 10 - 'A') << (4 * (1 - j))); + break; + + case 'a' ... 'f': + tmp |= ((data[*pos + j] + 10 - 'a') << (4 * (1 - j))); + break; + + default: + result = false; + break; + + } + + *pos += 2; + + switch (endian) + { + case SRE_LITTLE: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target64 |= ((uint64_t)tmp) << (8 * i); + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target64 |= ((uint64_t)tmp) << (8 * (n - 1 - i)); + +#endif + + break; + + case SRE_BIG: + +#if __BYTE_ORDER == __LITTLE_ENDIAN + + *target64 |= ((uint64_t)tmp) << (8 * (n - 1 - i)); + +#elif __BYTE_ORDER == __BIG_ENDIAN + + *target64 |= ((uint64_t)tmp) << (8 * i); + +#endif + + break; + + default: + return false; + break; + + } + + } + + return result; + +} |