/* Chrysalide - Outil d'analyse de fichiers binaires
* endianness.c - manipulation abstraite des nombres
*
* Copyright (C) 2009-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 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;
}