diff options
author | Cyrille Bagard <nocbos@gmail.com> | 2021-02-20 22:38:22 (GMT) |
---|---|---|
committer | Cyrille Bagard <nocbos@gmail.com> | 2021-02-20 22:38:22 (GMT) |
commit | 9a080bc3f8184a5663ce42c3c74ae80e1ae598a0 (patch) | |
tree | fa80229577a84afd58c1dc81ea599cd67036d771 /src | |
parent | 170dc35d87e0a858c5400937a1ee2d2dde7f653a (diff) |
Pack and unpack LEB128 values on demand.
Diffstat (limited to 'src')
-rw-r--r-- | src/common/leb128.c | 207 | ||||
-rw-r--r-- | src/common/leb128.h | 16 |
2 files changed, 222 insertions, 1 deletions
diff --git a/src/common/leb128.c b/src/common/leb128.c index c3f7466..c8d2ace 100644 --- a/src/common/leb128.c +++ b/src/common/leb128.c @@ -109,3 +109,210 @@ bool read_leb128(leb128_t *target, const bin_t *data, phys_t *pos, phys_t len) return (i < 8); } + + +/****************************************************************************** +* * +* Paramètres : value = valeur à consigner. * +* pbuf = tampon de données à constituer. [OUT] * +* * +* Description : Encode un nombre non signé encodé au format LEB128. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool pack_uleb128(const uleb128_t *value, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + uleb128_t tmp; /* Valeur modifiable */ + uint8_t byte; /* Octet à transposer */ + + tmp = *value; + + do + { + byte = (tmp & 0x7f); + tmp >>= 7; + + if (tmp != 0) + byte |= 0x80; + + result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); + + } + while (result && tmp != 0); + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : value = valeur à consigner. * +* pbuf = tampon de données à constituer. [OUT] * +* * +* Description : Encode un nombre signé encodé au format LEB128. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool pack_leb128(const leb128_t *value, packed_buffer_t *pbuf) +{ + + bool result; /* Bilan à retourner */ + uleb128_t tmp; /* Valeur modifiable */ + bool more; /* Poursuite des traitements */ + bool negative; /* Nature de la valeur */ + uint8_t byte; /* Octet à transposer */ + + tmp = *value; + + more = true; + negative = (*value < 0); + + while (more) + { + byte = (tmp & 0x7f); + tmp >>= 7; + + /** + * Propagation forcée du bit de signe pour les implémentations de + * décalage basées sur une opération logique et non arithmétique. + */ + + if (negative) + tmp |= (~0llu << (LEB128_BITS_COUNT - 7)); + + /** + * Le bit de signe n'est pas le bit de poids fort ici : + * On travaille sur 7 bits, donc le masque est 0x40 ! + */ + + if ((tmp == 0 && (byte & 0x40) == 0x00) || (tmp == -1 && (byte & 0x40) == 0x40)) + more = false; + + else + byte |= 0x80; + + result = extend_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : value = valeur à constituer. [OUT] * +* pbuf = tampon de données à consulter. * +* * +* Description : Décode un nombre non signé encodé au format LEB128. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool unpack_uleb128(uleb128_t *value, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + unsigned int shift; /* Décalage à appliquer */ + uint8_t byte; /* Octet à transposer */ + + result = true; + + *value = 0; + + shift = 0; + + while (true) + { + /* Encodage sur trop d'octets ? */ + if (shift > (7 * sizeof(uleb128_t))) + { + result = false; + break; + } + + result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); + if (!result) break; + + *value |= ((byte & 0x7f) << shift); + + if ((byte & 0x80) == 0x00) + break; + + shift += 7; + + } + + return result; + +} + + +/****************************************************************************** +* * +* Paramètres : value = valeur à constituer. [OUT] * +* pbuf = tampon de données à consulter. * +* * +* Description : Décode un nombre signé encodé au format LEB128. * +* * +* Retour : Bilan de l'opération : true en cas de succès, false sinon. * +* * +* Remarques : - * +* * +******************************************************************************/ + +bool unpack_leb128(leb128_t *value, packed_buffer_t *pbuf) +{ + bool result; /* Bilan à retourner */ + unsigned int shift; /* Décalage à appliquer */ + uint8_t byte; /* Octet à transposer */ + + result = true; + + *value = 0; + + shift = 0; + + do + { + /* Encodage sur trop d'octets ? */ + if (shift > (7 * sizeof(leb128_t))) + { + result = false; + break; + } + + result = extract_packed_buffer(pbuf, &byte, sizeof(uint8_t), false); + if (!result) break; + + *value |= ((byte & 0x7f) << shift); + + shift += 7; + + } + while ((byte & 0x80) == 0x80); + + /** + * Le bit de signe n'est pas le bit de poids fort ici : + * On travaille sur 7 bits, donc le masque est 0x40 ! + */ + + if (shift < LEB128_BITS_COUNT && (byte & 0x40) == 0x40) + *value |= (~0llu << shift); + + return result; + +} diff --git a/src/common/leb128.h b/src/common/leb128.h index 2093ead..ae1078a 100644 --- a/src/common/leb128.h +++ b/src/common/leb128.h @@ -29,6 +29,7 @@ #include <stdlib.h> +#include "packed.h" #include "../arch/archbase.h" #include "../arch/vmpa.h" @@ -39,10 +40,12 @@ typedef uint64_t uleb128_t; typedef int64_t leb128_t; +/* Quantité de bits utilisés */ +#define LEB128_BITS_COUNT (sizeof(leb128_t) * 8) + /* Récupération de la valeur absolue */ #define leb128_abs(v) llabs(v) - /* Valeurs minimales et maximales */ #define ULEB128_MIN UINT64_MIN #define ULEB128_MAX UINT64_MAX @@ -56,6 +59,17 @@ bool read_uleb128(uleb128_t *, const bin_t *, phys_t *, phys_t); /* Lit un nombre signé encodé au format LEB128. */ bool read_leb128(leb128_t *, const bin_t *, phys_t *, phys_t); +/* Encode un nombre non signé encodé au format LEB128. */ +bool pack_uleb128(const uleb128_t *, packed_buffer_t *); + +/* Encode un nombre signé encodé au format LEB128. */ +bool pack_leb128(const leb128_t *, packed_buffer_t *); + +/* Décode un nombre non signé encodé au format LEB128. */ +bool unpack_uleb128(uleb128_t *, packed_buffer_t *); + +/* Décode un nombre signé encodé au format LEB128. */ +bool unpack_leb128(leb128_t *, packed_buffer_t *); #endif /* _COMMON_LEB128_H */ |