/* Chrysalide - Outil d'analyse de fichiers binaires * endianness.c - manipulation abstraite des nombres * * Copyright (C) 2009-2012 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 "endianness.h" #include #include /****************************************************************************** * * * 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 (*pos < 0) return false; if ((end - *pos) < 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 (*pos < 0) return false; if ((end - *pos) < 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 (*pos < 0) return false; if ((end - *pos) < 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; #else # error "TODO : PDP !" #endif break; case SRE_MIDDLE: /* TODO */ 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; #else # error "TODO : PDP !" #endif 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 (*pos < 0) return false; if ((end - *pos) < 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; #else # error "TODO : PDP !" #endif break; case SRE_MIDDLE: /* TODO */ 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; #else # error "TODO : PDP !" #endif 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 (*pos < 0) return false; if ((end - *pos) < 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; #else # error "TODO : PDP !" #endif break; case SRE_MIDDLE: /* TODO */ 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; #else # error "TODO : PDP !" #endif 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 (*pos < 0) return false; if ((end - *pos) < 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); #else # error "TODO : PDP !" #endif break; case SRE_MIDDLE: return false; /* TODO ! */ 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; #else # error "TODO : PDP !" #endif 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 (*pos < 0) return false; if ((end - *pos) < 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 (*pos < 0) return false; if ((end - *pos) < (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)); #else # error "TODO : PDP !" #endif break; case SRE_MIDDLE: /* TODO */ 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); #else # error "TODO : PDP !" #endif break; } } return result; }