From 54d05927811a59db294af8a24258c0b837360492 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 3 Nov 2024 15:00:29 +0100
Subject: Load and store various values.

---
 src/common/bits.c   | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/common/bits.h   |   9 ++++
 src/common/fnv1a.c  |  33 ++++++++++++-
 src/common/fnv1a.h  |   6 ++-
 src/common/io.h     |  57 +++++++++++++++++++++++
 src/common/leb128.c |  93 +++++++++++++++++++++++++++++++++++++
 src/common/leb128.h |   6 +++
 src/common/szbin.h  | 129 ++++++++++++++++++++++++++++++++++++++++-----------
 8 files changed, 435 insertions(+), 29 deletions(-)

diff --git a/src/common/bits.c b/src/common/bits.c
index f730c66..26f570f 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -31,6 +31,7 @@
 
 
 #include "asm.h"
+#include "leb128.h"
 
 
 
@@ -1291,3 +1292,133 @@ void output_bit_field(const bitfield_t *field)
 }
 
 #endif
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : fd        = flux ouvert en lecture.                          *
+*                length    = éventuelle indication de la taille du champ ?    *
+*                def_state = éventuelle indication de l'état par défaut ?     *
+*                endian    = ordre des bits dans la source.                   *
+*                                                                             *
+*  Description : Restaure un champ de bits depuis un flux ouvert.             *
+*                                                                             *
+*  Retour      : Adresse du champs de bits mis en place, NULL en cas d'échec. *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bitfield_t *load_bit_field(int fd, const size_t *length, const bool *def_state, SourceEndian endian)
+{
+    bitfield_t *result;                     /* Structure à retourner       */
+    size_t final_length;                    /* Nombre de bits représentés  */
+    uleb128_t leb128_value;                 /* Valeur LEB128 chargée       */
+    bool status;                            /* Bilan d'une lecture         */
+    bool final_default_state;               /* Etat d'initialisation       */
+    uint8_t u8_value;                       /* Valeur sur 8 bits chargée   */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = NULL;
+
+    if (length != NULL)
+        final_length = *length;
+    else
+    {
+        status = load_uleb128(&leb128_value, fd);
+        if (!status) goto exit;
+
+        final_length = leb128_value;
+
+    }
+
+    if (def_state != NULL)
+        final_default_state = *def_state;
+
+    else
+    {
+        status = load_u8(fd, &u8_value);
+        if (!status) goto exit;
+
+        final_default_state = !!u8_value;
+
+    }
+
+    result = _create_bit_field(final_length);
+
+    result->default_state = final_default_state;
+
+    for (i = 0; i < result->used_words; i++)
+    {
+        status = load_uleb128(&leb128_value, fd);
+
+        if (status)
+            result->bits[i] = leb128_value;
+
+        else
+        {
+            delete_bit_field(result);
+            result =  NULL;
+            break;
+        }
+
+    }
+
+ exit:
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : field    = champ de bits à consulter.                        *
+*                fd       = flux ouvert en écriture.                          *
+*                skip_len = saute la sauvegarde de la taille du champ ?       *
+*                skip_def = saute la sauvegarde de l'état par défaut ?        *
+*                endian = ordre des bits dans la source.                      *
+*                                                                             *
+*  Description : Sauvegarde un champ de bits dans un flux ouvert.             *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool store_bit_field(const bitfield_t *field, int fd, bool skip_len, bool skip_def, SourceEndian endian)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+
+    if (skip_len)
+        result = true;
+    else
+    {
+        result = store_uleb128((const uleb128_t []) { field->length }, fd);
+        if (!result) goto exit;
+    }
+
+    if (skip_def)
+        result = true;
+    else
+    {
+        result = store_u8(fd, field->default_state);
+        if (!result) goto exit;
+    }
+
+    for (i = 0; i < field->used_words; i++)
+    {
+        result = store_uleb128((const uleb128_t []) { field->bits[i] }, fd);
+
+        if (!result)
+            break;
+
+    }
+
+ exit:
+
+    return result;
+
+}
diff --git a/src/common/bits.h b/src/common/bits.h
index 3898c73..d9c83c8 100644
--- a/src/common/bits.h
+++ b/src/common/bits.h
@@ -29,6 +29,9 @@
 #include <sys/types.h>
 
 
+#include "datatypes.h"
+
+
 
 /* Champ de bits simple */
 typedef struct _bitfield_t bitfield_t;
@@ -119,6 +122,12 @@ void output_bit_field(const bitfield_t *);
 
 #endif
 
+/* Restaure un champ de bits depuis un flux ouvert. */
+bitfield_t *load_bit_field(int, const size_t *, const bool *, SourceEndian);
+
+/* Sauvegarde un champ de bits dans un flux ouvert. */
+bool store_bit_field(const bitfield_t *, int, bool, bool, SourceEndian);
+
 
 
 #endif  /* _COMMON_BITS_H */
diff --git a/src/common/fnv1a.c b/src/common/fnv1a.c
index a8afd0a..057d6c9 100644
--- a/src/common/fnv1a.c
+++ b/src/common/fnv1a.c
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * fnv1a.c - implémentaton du calcul rapide d'empreintes de chaînes
  *
- * Copyright (C) 2012-2018 Cyrille Bagard
+ * Copyright (C) 2012-2024 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -87,3 +87,34 @@ fnv64_t fnv_64a_hash(const char *str)
     return result;
 
 }
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : data = données binaires à traiter.                           *
+*                size = quantité de ces données.                              *
+*                                                                             *
+*  Description : Détermine l'empreinte FNV1a d'une séquence d'octets.         *
+*                                                                             *
+*  Retour      : Valeur calculée.                                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+fnv64_t fnv_64a_hash_data(const uint8_t *data, size_t size)
+{
+    fnv64_t result;                         /* Valeur à retourner          */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = FNV1A_64_INIT;
+
+    for (i = 0; i < size; i++)
+    {
+        result ^= (fnv64_t)data[i];
+        result *= FNV_64_PRIME;
+    }
+
+    return result;
+
+}
diff --git a/src/common/fnv1a.h b/src/common/fnv1a.h
index eec1460..4da3108 100644
--- a/src/common/fnv1a.h
+++ b/src/common/fnv1a.h
@@ -2,7 +2,7 @@
 /* Chrysalide - Outil d'analyse de fichiers binaires
  * fnv1a.h - prototypes pour l'implémentaton du calcul rapide d'empreintes de chaînes
  *
- * Copyright (C) 2012-2018 Cyrille Bagard
+ * Copyright (C) 2012-2024 Cyrille Bagard
  *
  *  This file is part of Chrysalide.
  *
@@ -27,6 +27,7 @@
 
 #include <stdbool.h>
 #include <stdint.h>
+#include <sys/types.h>
 
 
 /**
@@ -46,6 +47,9 @@ int cmp_fnv_64a(fnv64_t, fnv64_t);
 /* Détermine l'empreinte FNV1a d'une chaîne de caractères. */
 fnv64_t fnv_64a_hash(const char *);
 
+/* Détermine l'empreinte FNV1a d'une séquence d'octets. */
+fnv64_t fnv_64a_hash_data(const uint8_t *, size_t);
+
 
 
 #endif  /* _COMMON_FNV1A_H */
diff --git a/src/common/io.h b/src/common/io.h
index 7fe9d9d..1932b12 100644
--- a/src/common/io.h
+++ b/src/common/io.h
@@ -39,12 +39,69 @@
 /* Lit des données depuis un flux local. */
 bool safe_read(int, void *, size_t);
 
+#define load_u8(f, v) \
+    safe_read(f, v, sizeof(uint8_t));
+
+#define load_u16(f, v, e)                               \
+    ({                                                  \
+        bool __ret;                                     \
+        uint16_t __val;                                 \
+        __ret = safe_read(f, &__val, sizeof(uint16_t)); \
+        __val = swap_u16(&__val, e);                    \
+        *(v) = __val;                                   \
+        __ret;                                          \
+    })
+
+#define load_u32(f, v, e)                               \
+    ({                                                  \
+        bool __ret;                                     \
+        uint32_t __val;                                 \
+        __ret = safe_read(f, &__val, sizeof(uint32_t)); \
+        __val = swap_u32(&__val, e);                    \
+        *(v) = __val;                                   \
+        __ret;                                          \
+    })
+
+#define load_u64(f, v, e)                               \
+    ({                                                  \
+        bool __ret;                                     \
+        uint64_t __val;                                 \
+        __ret = safe_read(f, &__val, sizeof(uint64_t)); \
+        __val = swap_u64(&__val, e);                    \
+        *(v) = __val;                                   \
+        __ret;                                          \
+    })
+
 /* Lit des données depuis un flux local. */
 ssize_t safe_read_partial(int, void *, size_t);
 
 /* Ecrit des données dans un flux local. */
 bool safe_write(int, const void *, size_t);
 
+#define store_u8(f, v) \
+    safe_write(f, (const uint8_t []){ v }, sizeof(uint8_t));
+
+#define store_u16(f, v, e)                              \
+    ({                                                  \
+        uint16_t __val;                                 \
+        __val = swap_u16((const uint16_t []){ v }, e);  \
+        safe_write(f, &__val, sizeof(uint16_t));        \
+    })
+
+#define store_u32(f, v, e)                              \
+    ({                                                  \
+        uint32_t __val;                                 \
+        __val = swap_u32((const uint32_t []){ v }, e);  \
+        safe_write(f, &__val, sizeof(uint32_t));        \
+    })
+
+#define store_u64(f, v, e)                              \
+    ({                                                  \
+        uint64_t __val;                                 \
+        __val = swap_u64((const uint64_t []){ v }, e);  \
+        safe_write(f, &__val, sizeof(uint64_t));        \
+    })
+
 /* Réceptionne des données depuis un flux réseau. */
 bool safe_recv(int, void *, size_t, int);
 
diff --git a/src/common/leb128.c b/src/common/leb128.c
index c8d2ace..009aff6 100644
--- a/src/common/leb128.c
+++ b/src/common/leb128.c
@@ -24,6 +24,9 @@
 #include "leb128.h"
 
 
+#include "io.h"
+
+
 
 /******************************************************************************
 *                                                                             *
@@ -113,6 +116,96 @@ bool read_leb128(leb128_t *target, const bin_t *data, phys_t *pos, phys_t len)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : value = valeur à constituer. [OUT]                           *
+*                fd    = flux ouvert en lecture à consulter.                  *
+*                                                                             *
+*  Description : Restaure un nombre non signé encodé au format LEB128.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool load_uleb128(uleb128_t *value, int fd)
+{
+    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 = safe_read(fd, &byte, sizeof(uint8_t));
+        if (!result) break;
+
+        *value |= ((byte & 0x7f) << shift);
+
+        if ((byte & 0x80) == 0x00)
+            break;
+
+        shift += 7;
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : value = valeur à consigner.                                  *
+*                fd    = flux ouvert en écriture.                             *
+*                                                                             *
+*  Description : Sauvegarde un nombre non signé encodé au format LEB128.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération : true en cas de succès, false sinon.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool store_uleb128(const uleb128_t *value, int fd)
+{
+    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 = safe_write(fd, &byte, sizeof(uint8_t));
+
+    }
+    while (result && tmp != 0);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : value = valeur à consigner.                                  *
 *                pbuf  = tampon de données à constituer. [OUT]                *
 *                                                                             *
diff --git a/src/common/leb128.h b/src/common/leb128.h
index f438068..0313f5c 100644
--- a/src/common/leb128.h
+++ b/src/common/leb128.h
@@ -58,6 +58,12 @@ 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);
 
+/* Charge un nombre non signé encodé au format LEB128. */
+bool load_uleb128(uleb128_t *, int);
+
+/* Sauvegarde un nombre non signé encodé au format LEB128. */
+bool store_uleb128(const uleb128_t *, int);
+
 /* Encode un nombre non signé encodé au format LEB128. */
 bool pack_uleb128(const uleb128_t *, packed_buffer_t *);
 
diff --git a/src/common/szbin.h b/src/common/szbin.h
index ac938ab..5891449 100644
--- a/src/common/szbin.h
+++ b/src/common/szbin.h
@@ -29,6 +29,12 @@
 #include <string.h>
 
 
+#include "datatypes.h"
+#include "io.h"
+#include "leb128.h"
+#include "sort.h"
+
+
 
 /* Structure associant données et taille */
 typedef struct _sized_binary_t
@@ -38,6 +44,9 @@ typedef struct _sized_binary_t
         const char *static_data;        /* Données non modifiées       */
         char *data;                     /* Chaîne de caractères        */
 
+        const bin_t *static_bin_data;   /* Données brutes non modifiées*/
+        bin_t *bin_data;                /* Données brutes              */
+
     };
 
     size_t size;                        /* Taille correspondante       */
@@ -45,44 +54,110 @@ typedef struct _sized_binary_t
 } sized_binary_t;
 
 
-#define init_sized_binary(sb)           \
-    do                                  \
-    {                                   \
-        (sb)->data = NULL;              \
-        (sb)->size = 0;                 \
-    }                                   \
+#define init_sized_binary(sb)               \
+    do                                      \
+    {                                       \
+        (sb)->data = NULL;                  \
+        (sb)->size = 0;                     \
+    }                                       \
     while (0)
 
 
-#define setup_sized_binary(sb, s)       \
-    do                                  \
-    {                                   \
-        (sb)->data = malloc(s);         \
-        (sb)->size = s;                 \
-    }                                   \
+#define setup_sized_binary(sb, s)           \
+    do                                      \
+    {                                       \
+        (sb)->data = malloc(s);             \
+        (sb)->size = s;                     \
+    }                                       \
     while (0)
 
 
-#define dup_into_sized_binary(sb, d, s) \
-    do                                  \
-    {                                   \
-        setup_sized_binary(sb, s);      \
-        memcpy((sb)->data, d, s);       \
-    }                                   \
+#define dup_into_sized_binary(sb, d, s)     \
+    do                                      \
+    {                                       \
+        setup_sized_binary(sb, s);          \
+        memcpy((sb)->data, d, s);           \
+    }                                       \
     while (0)
 
 
-#define exit_sized_binary(sb)           \
-    do                                  \
-    {                                   \
-        if ((sb)->data != NULL)         \
-        {                               \
-            free((sb)->data);           \
-            init_sized_binary(sb);      \
-        }                               \
-    }                                   \
+#define dup_sized_binary(dst, src)          \
+    dup_into_sized_binary((dst), (src)->static_data, (src)->size)
+
+
+#define exit_sized_binary(sb)               \
+    do                                      \
+    {                                       \
+        if ((sb)->data != NULL)             \
+        {                                   \
+            free((sb)->data);               \
+            init_sized_binary(sb);          \
+        }                                   \
+    }                                       \
     while (0)
 
 
+#define add_to_sized_binary(sb, d, s)       \
+    do                                      \
+    {                                       \
+        size_t __old_size;                  \
+        __old_size = (sb)->size;            \
+        (sb)->size += s;                    \
+        (sb)->data = realloc((sb)->data,    \
+                             (sb)->size);   \
+        memcpy((sb)->data + __old_size,     \
+               d, s);                       \
+    }                                       \
+    while (0)
+
+
+#define add_static_to_sized_binary(sb, d)   \
+    do                                      \
+    {                                       \
+        size_t __len;                       \
+        __len = sizeof(d) - 1;              \
+        add_to_sized_binary(sb, d, __len);  \
+    }                                       \
+    while (0)
+
+
+#define memcmp_sized_binary(s1, s2)                                 \
+    ({                                                              \
+        int __ret;                                                  \
+        size_t __n;                                                 \
+        __n = (s1)->size < (s2)->size ? (s1)->size : (s2)->size;    \
+        __ret = memcmp((s1)->data, (s2)->data, __n);                \
+        if (__ret == 0)                                             \
+            __ret = sort_unsigned_long_long((s1)->size, (s2)->size);\
+        __ret;                                                      \
+    })
+
+
+#define load_sized_binary(sb, f)                                        \
+    ({                                                                  \
+        uleb128_t __sz;                                                 \
+        bool __ret;                                                     \
+        __ret = load_uleb128(&__sz, f);                                 \
+        if (__ret)                                                      \
+        {                                                               \
+            setup_sized_binary(sb, __sz);                               \
+            __ret = safe_read(f, (sb)->data, (sb)->size);               \
+            if (!__ret)                                                 \
+                exit_sized_binary(sb);                                  \
+        }                                                               \
+        __ret;                                                          \
+    })
+
+
+#define store_sized_binary(sb, f)                                       \
+    ({                                                                  \
+        bool __ret;                                                     \
+        __ret = store_uleb128((const uleb128_t []){ (sb)->size }, f);   \
+        if (__ret)                                                      \
+            __ret = safe_write(f, (sb)->static_data, (sb)->size);       \
+        __ret;                                                          \
+    })
+
+
 
 #endif  /* _COMMON_SZBIN_H */
-- 
cgit v0.11.2-87-g4458