From 0ff1e52622828663d01f98c97f2cd8eccb8facf8 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Sun, 21 Jan 2024 23:36:47 +0100
Subject: Refactor the scan match storage.

---
 plugins/pychrysalide/analysis/scan/context.c       |   2 +-
 src/Makefile.am                                    |   3 +-
 src/analysis/scan/Makefile.am                      |   4 +-
 src/analysis/scan/context-int.h                    |  31 +-
 src/analysis/scan/context.c                        | 374 ++-------
 src/analysis/scan/context.h                        |  34 +-
 src/analysis/scan/exprs/handler.c                  |  55 +-
 src/analysis/scan/exprs/handler.h                  |   4 +
 src/analysis/scan/exprs/setcounter.c               |  15 +-
 src/analysis/scan/items/modpath.c                  |   7 +
 src/analysis/scan/match-int.h                      |  60 --
 src/analysis/scan/match.c                          | 263 ------
 src/analysis/scan/match.h                          |  71 --
 src/analysis/scan/matches-int.h                    |  65 ++
 src/analysis/scan/matches.c                        | 268 ++++++
 src/analysis/scan/matches.h                        |  74 ++
 src/analysis/scan/matches/Makefile.am              |   4 +-
 src/analysis/scan/matches/area.c                   |  57 ++
 src/analysis/scan/matches/area.h                   |  85 ++
 src/analysis/scan/matches/bytes-int.h              |  31 +-
 src/analysis/scan/matches/bytes.c                  | 595 +++++++++-----
 src/analysis/scan/matches/bytes.h                  |  58 +-
 src/analysis/scan/matches/pending.c                | 150 +++-
 src/analysis/scan/matches/pending.h                |  11 +-
 src/analysis/scan/pattern.c                        |   2 +-
 src/analysis/scan/patterns/Makefile.am             |   1 +
 src/analysis/scan/patterns/backend-int.h           |  14 +-
 src/analysis/scan/patterns/backend.c               |  61 +-
 src/analysis/scan/patterns/backend.h               |   8 +-
 src/analysis/scan/patterns/backends/acism-int.h    |  13 +-
 src/analysis/scan/patterns/backends/acism.c        | 174 +++-
 src/analysis/scan/patterns/backends/bitap.c        |  12 +-
 src/analysis/scan/patterns/patid.h                 |  36 +
 src/analysis/scan/patterns/token.c                 | 176 ++--
 src/analysis/scan/patterns/token.h                 |   9 +-
 src/analysis/scan/patterns/tokens/atom.c           | 103 ++-
 src/analysis/scan/patterns/tokens/atom.h           |  27 +-
 src/analysis/scan/patterns/tokens/node-int.h       |  33 +-
 src/analysis/scan/patterns/tokens/node.c           | 195 +++--
 src/analysis/scan/patterns/tokens/node.h           |  55 +-
 src/analysis/scan/patterns/tokens/nodes/any.c      | 461 +++++++++--
 src/analysis/scan/patterns/tokens/nodes/choice.c   | 342 +++++---
 .../scan/patterns/tokens/nodes/masked-int.h        |   5 +-
 src/analysis/scan/patterns/tokens/nodes/masked.c   | 735 +++++++++++------
 src/analysis/scan/patterns/tokens/nodes/masked.h   |   9 -
 src/analysis/scan/patterns/tokens/nodes/not.c      |  98 ++-
 src/analysis/scan/patterns/tokens/nodes/plain.c    | 902 ++++++++++++++++-----
 src/analysis/scan/patterns/tokens/nodes/sequence.c | 116 ++-
 src/analysis/scan/patterns/tokens/offset.c         |  86 ++
 src/analysis/scan/patterns/tokens/offset.h         |  12 +-
 src/analysis/scan/rule.c                           |  80 +-
 src/analysis/scan/rule.h                           |   3 +
 src/analysis/scan/scanner.c                        |  51 +-
 tests/analysis/scan/scanning_hex.py                |   5 +-
 54 files changed, 4148 insertions(+), 1997 deletions(-)
 delete mode 100644 src/analysis/scan/match-int.h
 delete mode 100644 src/analysis/scan/match.c
 delete mode 100644 src/analysis/scan/match.h
 create mode 100644 src/analysis/scan/matches-int.h
 create mode 100644 src/analysis/scan/matches.c
 create mode 100644 src/analysis/scan/matches.h
 create mode 100644 src/analysis/scan/matches/area.c
 create mode 100644 src/analysis/scan/matches/area.h
 create mode 100644 src/analysis/scan/patterns/patid.h

diff --git a/plugins/pychrysalide/analysis/scan/context.c b/plugins/pychrysalide/analysis/scan/context.c
index 7071935..9becaf7 100644
--- a/plugins/pychrysalide/analysis/scan/context.c
+++ b/plugins/pychrysalide/analysis/scan/context.c
@@ -254,7 +254,7 @@ static int py_scan_context_set_content(PyObject *self, PyObject *value, void *cl
     context = G_SCAN_CONTEXT(pygobject_get(self));
     content = G_BIN_CONTENT(pygobject_get(value));
 
-    g_scan_context_set_content(context, content);
+    // FIXME g_scan_context_set_content(context, content);
 
     return 0;
 
diff --git a/src/Makefile.am b/src/Makefile.am
index 4aed32e..e7aa395 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -54,8 +54,9 @@ libchrysacore_la_LIBADD =					\
 
 
 # -ldl: dladdr(), dlerror()
+# -lm : pow()
 libchrysacore_la_LDFLAGS =					\
-	-avoid-version -ldl						\
+	-avoid-version -ldl -lm					\
 	$(TOOLKIT_LIBS) $(LIBXML_LIBS)			\
 	$(LIBSQLITE_LIBS) $(LIBARCHIVE_LIBS)	\
 	$(LIBSSL_LIBS)
diff --git a/src/analysis/scan/Makefile.am b/src/analysis/scan/Makefile.am
index d24f4a8..ed4f8c7 100644
--- a/src/analysis/scan/Makefile.am
+++ b/src/analysis/scan/Makefile.am
@@ -26,8 +26,8 @@ libanalysisscan_la_SOURCES =				\
 	expr.h expr.c							\
 	item-int.h								\
 	item.h item.c							\
-	match-int.h								\
-	match.h match.c							\
+	matches-int.h							\
+	matches.h matches.c						\
 	options-int.h							\
 	options.h options.c						\
 	pattern-int.h							\
diff --git a/src/analysis/scan/context-int.h b/src/analysis/scan/context-int.h
index 613ca73..efbd24e 100644
--- a/src/analysis/scan/context-int.h
+++ b/src/analysis/scan/context-int.h
@@ -33,28 +33,6 @@
 
 
 
-#define ALLOCATION_STEP 10
-
-/* Mémorisation des correspondances partielles */
-typedef struct _atom_match_tracker_t
-{
-    phys_t *matches;                        /* Correspondances à confirmer */
-    size_t allocated;                       /* Taille du talbeau préparé   */
-    size_t used;                            /* Nombre d'éléments présents  */
-
-} atom_match_tracker_t;
-
-/* Mémorisation des correspondances complètes, par motif */
-typedef struct _full_match_tracker_t
-{
-    GSearchPattern *pattern;                /* Motif commun aux trouvailles*/
-
-    GScanMatch **matches;                   /* Correspondances confirmées  */
-    size_t allocated;                       /* Taille du talbeau préparé   */
-    size_t used;                            /* Nombre d'éléments présents  */
-
-} full_match_tracker_t;
-
 /* Condition définissant une règle de correspondance */
 typedef struct _rule_condition_t
 {
@@ -76,13 +54,10 @@ struct _GScanContext
     GBinContent *content;                   /* Contenu binaire traité      */
     bool scan_done;                         /* Phase d'analyse terminée ?  */
 
-    patid_t next_patid;                     /* Prochain indice utilisable  */
-
-    atom_match_tracker_t *atom_trackers;    /* Correspondances partielles  */
+    GUMemSlice **match_storages;            /* Suivi de correspondances    */
+    size_t storages_count;                  /* Quantité de ces suivis      */
 
-    full_match_tracker_t **full_trackers;   /* Correspondances confirmées  */
-    size_t full_count;                      /* Quantité de correspondances */
-    full_match_tracker_t *current_tracker;  /* Dernier gestionnaire visé   */
+    GHashTable *full_trackers;              /* Correspondances confirmées  */
 
     bool global;                            /* Validation globale          */
 
diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c
index 94ea519..55311c4 100644
--- a/src/analysis/scan/context.c
+++ b/src/analysis/scan/context.c
@@ -32,32 +32,12 @@
 
 #include "context-int.h"
 #include "exprs/literal.h"
+#include "matches/area.h"
+#include "matches/bytes.h"
 #include "../../common/sort.h"
 
 
 
-
-
-/* ------------------- ADMINISTRATION DES CORRESPONDANCES TOTALES ------------------- */
-
-
-/* Initialise un suivi de trouvailles pour un premier motif. */
-static full_match_tracker_t *create_full_match_tracker(GSearchPattern *);
-
-/* Termine le suivi de trouvailles pour un motif. */
-static void delete_full_match_tracker(full_match_tracker_t *);
-
-/* Etablit la comparaison entre deux structures de suivi. */
-static int compare_full_match_trackers(const full_match_tracker_t **, const full_match_tracker_t **);
-
-/* Prépare l'intégration d'une série de correspondances. */
-static void prepare_full_match_tracker(full_match_tracker_t *, size_t);
-
-/* Note l'existence d'une nouvelle correspondance pour un motif. */
-static void add_match_to_full_match_tracker(full_match_tracker_t *, GScanMatch *);
-
-
-
 /* --------------------- MEMORISATION DE PROGRESSIONS D'ANALYSE --------------------- */
 
 
@@ -76,145 +56,6 @@ static void g_scan_context_finalize(GScanContext *);
 
 
 /* ---------------------------------------------------------------------------------- */
-/*                     ADMINISTRATION DES CORRESPONDANCES TOTALES                     */
-/* ---------------------------------------------------------------------------------- */
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : pattern = motif de recherche trouvé.                         *
-*                                                                             *
-*  Description : Initialise un suivi de trouvailles pour un premier motif.    *
-*                                                                             *
-*  Retour      : Structure de suivi mise en place.                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static full_match_tracker_t *create_full_match_tracker(GSearchPattern *pattern)
-{
-    full_match_tracker_t *result;           /* Structure à retourner       */
-
-    result = malloc(sizeof(full_match_tracker_t));
-
-    result->pattern = pattern;
-    g_object_ref(G_OBJECT(pattern));
-
-    result->matches = malloc(ALLOCATION_STEP * sizeof(GScanMatch *));
-    result->allocated = ALLOCATION_STEP;
-    result->used = 0;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : tracker = structure de gestion à manipuler.                  *
-*                                                                             *
-*  Description : Termine le suivi de trouvailles pour un motif.               *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void delete_full_match_tracker(full_match_tracker_t *tracker)
-{
-    size_t i;                               /* Boucle de parcours          */
-
-    g_object_unref(G_OBJECT(tracker->pattern));
-
-    for (i = 0; i < tracker->used; i++)
-        g_object_unref(G_OBJECT(tracker->matches[i]));
-
-    free(tracker->matches);
-
-    free(tracker);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : a = première structure de suivi à consulter.                 *
-*                b = seconde structure de suivi à consulter.                  *
-*                                                                             *
-*  Description : Etablit la comparaison entre deux structures de suivi.       *
-*                                                                             *
-*  Retour      : Bilan : -1 (a < b), 0 (a == b) ou 1 (a > b).                 *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static int compare_full_match_trackers(const full_match_tracker_t **a, const full_match_tracker_t **b)
-{
-    int result;                             /* Bilan à renvoyer            */
-
-    result = sort_unsigned_long((unsigned long)(*a)->pattern, (unsigned long)(*b)->pattern);
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : tracker  = structure de gestion à manipuler.                 *
-*                expected = quantité totale de correspondances attendue.      *
-*                                                                             *
-*  Description : Prépare l'intégration d'une série de correspondances.        *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void prepare_full_match_tracker(full_match_tracker_t *tracker, size_t expected)
-{
-    if ((tracker->used + expected) > tracker->allocated)
-    {
-        tracker->allocated += expected;
-        tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(GScanMatch *));
-    }
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : tracker = structure de gestion à manipuler.                  *
-*                match   = correspondance complète établie.                   *
-*                                                                             *
-*  Description : Note l'existence d'une nouvelle correspondance pour un motif.*
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void add_match_to_full_match_tracker(full_match_tracker_t *tracker, GScanMatch *match)
-{
-    if (tracker->used == tracker->allocated)
-    {
-        tracker->allocated += ALLOCATION_STEP;
-        tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(GScanMatch *));
-    }
-
-    tracker->matches[tracker->used++] = match;
-    g_object_ref(G_OBJECT(match));
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
 /*                       MEMORISATION DE PROGRESSIONS D'ANALYSE                       */
 /* ---------------------------------------------------------------------------------- */
 
@@ -266,13 +107,10 @@ static void g_scan_context_init(GScanContext *context)
     context->content = NULL;
     context->scan_done = false;
 
-    context->next_patid = 0;
-
-    context->atom_trackers = NULL;
+    context->match_storages = NULL;
+    context->storages_count = 0;
 
-    context->full_trackers = NULL;
-    context->full_count = 0;
-    context->current_tracker = NULL;
+    context->full_trackers = g_hash_table_new_full(NULL, NULL, g_object_unref, g_object_unref);
 
     context->global = true;
 
@@ -302,12 +140,14 @@ static void g_scan_context_dispose(GScanContext *context)
 
     g_clear_object(&context->content);
 
-    for (i = 0; i < context->full_count; i++)
-        if (context->full_trackers[i] != NULL)
-        {
-            delete_full_match_tracker(context->full_trackers[i]);
-            context->full_trackers[i] = NULL;
-        }
+    for (i = 0; i < context->storages_count; i++)
+        g_clear_object(&context->match_storages[i]);
+
+    if (context->full_trackers != NULL)
+    {
+        g_hash_table_destroy(context->full_trackers);
+        context->full_trackers = NULL;
+    }
 
     for (i = 0; i < context->cond_count; i++)
         g_clear_object(&context->conditions[i].expr);
@@ -332,25 +172,9 @@ static void g_scan_context_dispose(GScanContext *context)
 static void g_scan_context_finalize(GScanContext *context)
 {
     size_t i;                               /* Boucle de parcours          */
-    atom_match_tracker_t *atracker;         /* Conservateur à manipuler #1 */
 
-    if (context->atom_trackers != NULL)
-    {
-        for (i = 0; i < context->next_patid; i++)
-        {
-            atracker = context->atom_trackers + i;
-
-            if (atracker->matches != NULL)
-                free(atracker->matches);
-
-        }
-
-        free(context->atom_trackers);
-
-    }
-
-    if (context->full_trackers != NULL)
-        free(context->full_trackers);
+    if (context->match_storages != NULL)
+        free(context->match_storages);
 
     if (context->conditions != NULL)
     {
@@ -419,31 +243,9 @@ GScanOptions *g_scan_context_get_options(const GScanContext *context)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : context = instance à consulter.                              *
-*                                                                             *
-*  Description : Fournit un identifiant unique pour un motif recherché.       *
-*                                                                             *
-*  Retour      : Identifiant nouveau à utiliser.                              *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-patid_t g_scan_context_get_new_pattern_id(GScanContext *context)
-{
-    patid_t result;                         /* Identifiant à retourner     */
-
-    result = context->next_patid++;
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : context = instance à consulter.                              *
-*                content = contenu binaire en cours d'analyse.                *
+*  Paramètres  : context   = instance à consulter.                            *
+*                content   = contenu binaire en cours d'analyse.              *
+*                ids_count = nombre d'identifiants enregistrés.               *
 *                                                                             *
 *  Description : Définit le contenu principal à analyser.                     *
 *                                                                             *
@@ -453,15 +255,21 @@ patid_t g_scan_context_get_new_pattern_id(GScanContext *context)
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_context_set_content(GScanContext *context, GBinContent *content)
+void g_scan_context_set_content(GScanContext *context, GBinContent *content, size_t ids_count)
 {
+    size_t i;                               /* Boucle de parcours          */
+
     g_clear_object(&context->content);
 
     context->content = content;
 
     g_object_ref(G_OBJECT(content));
 
-    context->atom_trackers = calloc(context->next_patid, sizeof(atom_match_tracker_t));
+    context->match_storages = calloc(ids_count, sizeof(GUMemSlice *));
+    context->storages_count = ids_count;
+
+    for (i = 0; i < ids_count; i++)
+        context->match_storages[i] = g_umem_slice_new(sizeof(match_area_t));
 
 }
 
@@ -536,30 +344,25 @@ void g_scan_context_mark_scan_as_done(GScanContext *context)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : context = instance à mettre à jour.                          *
-*                id      = identifiant du motif trouvé.                       *
-*                offset  = localisation du motif au sein d'un contenu.        *
+*                count   = nombre d'allocateurs en place. [OUT]               *
 *                                                                             *
-*  Description : Enregistre une correspondance partielle dans un contenu.     *
+*  Description : Fournit la liste des allocateurs mémorisant des emplacements.*
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Liste des allocateurs assurant un suivi des correspondances. *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_context_register_atom_match(GScanContext *context, patid_t id, phys_t offset)
+GUMemSlice **g_scan_context_get_match_storages(GScanContext *context, size_t *count)
 {
-    atom_match_tracker_t *tracker;          /* Gestionnaire concerné       */
+    GUMemSlice **result;                    /* Allocateur à renvoyer       */
 
-    tracker = &context->atom_trackers[id];
+    result = context->match_storages;
 
-    if (tracker->used == tracker->allocated)
-    {
-        tracker->allocated += ALLOCATION_STEP;
-        tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(phys_t));
-    }
+    *count = context->storages_count;
 
-    tracker->matches[tracker->used++] = offset;
+    return result;
 
 }
 
@@ -568,7 +371,6 @@ void g_scan_context_register_atom_match(GScanContext *context, patid_t id, phys_
 *                                                                             *
 *  Paramètres  : context = instance à mettre à jour.                          *
 *                id      = identifiant du motif trouvé.                       *
-*                count   = nombre de localisations renvoyées. [OUT]           *
 *                                                                             *
 *  Description : Retourne tous les correspondances partielles notées.         *
 *                                                                             *
@@ -578,15 +380,13 @@ void g_scan_context_register_atom_match(GScanContext *context, patid_t id, phys_
 *                                                                             *
 ******************************************************************************/
 
-const phys_t *g_scan_context_get_atom_matches(const GScanContext *context, patid_t id, size_t *count)
+GUMemSlice *g_scan_context_get_atom_matches(const GScanContext *context, patid_t id)
 {
-    const phys_t *result;                   /* Liste constituée à renvoyer */
-    atom_match_tracker_t *tracker;          /* Gestionnaire concerné       */
+    GUMemSlice *result;              /* Liste constituée à renvoyer */
 
-    tracker = &context->atom_trackers[id];
+    result = context->match_storages[id];
 
-    result = tracker->matches;
-    *count = tracker->used;
+    g_object_ref(G_OBJECT(result));
 
     return result;
 
@@ -595,11 +395,11 @@ const phys_t *g_scan_context_get_atom_matches(const GScanContext *context, patid
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : context  = instance à mettre à jour.                         *
-*                match    = représentation d'une plein ecorrespondance.       *
-*                expected = quantité totale de correspondances attendue.      *
+*  Paramètres  : context = instance à mettre à jour.                          *
+*                pattern = definition initiale d'un motif recherché.          *
+*                matches = mémorisation de correspondances établies.          *
 *                                                                             *
-*  Description : Prépare les enregistrements de correspondances complètes.    *
+*  Description : Enregistre toutes les correspondances établies pour un motif.*
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -607,32 +407,28 @@ const phys_t *g_scan_context_get_atom_matches(const GScanContext *context, patid
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_context_prepare_full_match_registration(GScanContext *context, GSearchPattern *pattern, size_t expected)
+void g_scan_context_register_full_matches(GScanContext *context, GSearchPattern *pattern, GScanMatches *matches)
 {
-    full_match_tracker_t key;               /* Modèle d'identification     */
-    full_match_tracker_t **found;           /* Structure à actualiser      */
-    full_match_tracker_t *tracker;          /* Nouveau suivi à intégrer    */
+#ifndef NDEBUG
+    GSearchPattern *matches_pattern;        /* Clef d'un suivi             */
+#endif
 
-    key.pattern = pattern;
+    assert(!g_hash_table_contains(context->full_trackers, pattern));
 
-    found = bsearch((full_match_tracker_t *[]) { &key }, context->full_trackers, context->full_count,
-                    sizeof(full_match_tracker_t *), (__compar_fn_t)compare_full_match_trackers);
+#ifndef NDEBUG
 
-    if (found == NULL)
-    {
-        tracker = create_full_match_tracker(pattern);
+    matches_pattern = g_scan_matches_get_source(matches);
 
-        context->full_trackers = qinsert(context->full_trackers, &context->full_count,
-                                         sizeof(full_match_tracker_t *),
-                                         (__compar_fn_t)compare_full_match_trackers, &tracker);
+    assert(matches_pattern == pattern);
 
-    }
-    else
-        tracker = *found;
+    g_object_unref(G_OBJECT(matches_pattern));
 
-    prepare_full_match_tracker(tracker, expected);
+#endif
 
-    context->current_tracker = tracker;
+    g_object_ref(G_OBJECT(pattern));
+    g_object_ref(G_OBJECT(matches));
+
+    g_hash_table_insert(context->full_trackers, pattern, matches);
 
 }
 
@@ -640,36 +436,26 @@ void g_scan_context_prepare_full_match_registration(GScanContext *context, GSear
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : context = instance à mettre à jour.                          *
-*                match   = représentation d'une plein ecorrespondance.        *
+*                pattern = motif dont des correspondances sont à retrouver.   *
 *                                                                             *
-*  Description : Enregistre une correspondance complète avec un contenu.      *
+*  Description : Fournit la liste de toutes les correspondances pour un motif.*
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Liste courante de correspondances établies.                  *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match)
+GScanMatches *g_scan_context_get_full_matches(const GScanContext *context, const GSearchPattern *pattern)
 {
-#ifndef NDEBUG
-    GSearchPattern *pattern;                /* Clef d'un suivi             */
-#endif
-
-    assert(context->current_tracker != NULL);
-
-#ifndef NDEBUG
-
-    pattern = g_scan_match_get_source(match);
+    GScanMatches *result;                   /* Correspondance à renvoyer   */
 
-    assert(context->current_tracker->pattern == pattern);
+    result = g_hash_table_lookup(context->full_trackers, pattern);
 
-    g_object_unref(G_OBJECT(pattern));
+    if (result != NULL)
+        g_object_ref(G_OBJECT(result));
 
-
-#endif
-
-    add_match_to_full_match_tracker(context->current_tracker, match);
+    return result;
 
 }
 
@@ -678,38 +464,26 @@ void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match
 *                                                                             *
 *  Paramètres  : context = instance à mettre à jour.                          *
 *                pattern = motif dont des correspondances sont à retrouver.   *
-*                count   = quantité de correspondances enregistrées. [OUT]    *
 *                                                                             *
-*  Description : Fournit la liste de toutes les correspondances d'un motif.   *
+*  Description : Dénombre les correspondances associées à un motif.           *
 *                                                                             *
-*  Retour      : Liste courante de correspondances établies.                  *
+*  Retour      : Quantité de correspondances établies pour un motif entier.   *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-const GScanMatch **g_scan_context_get_full_matches(const GScanContext *context, const GSearchPattern *pattern, size_t *count)
+size_t g_scan_context_count_full_matches(const GScanContext *context, const GSearchPattern *pattern)
 {
-    GScanMatch **result;                    /* Correspondance à renvoyer   */
-    full_match_tracker_t key;               /* Modèle d'identification     */
-    full_match_tracker_t **found;           /* Structure à actualiser      */
-
-    key.pattern = pattern;
+    size_t result;                          /* Quantité à retourner        */
+    GScanMatches *matches;                  /* Ensemble de Correspondances */
 
-    found = bsearch((full_match_tracker_t *[]) { &key }, context->full_trackers, context->full_count,
-                    sizeof(full_match_tracker_t *), (__compar_fn_t)compare_full_match_trackers);
-
-    if (found == NULL)
-    {
-        result = NULL;
-        *count = 0;
-    }
+    matches = g_hash_table_lookup(context->full_trackers, pattern);
 
+    if (matches != NULL)
+        result = g_scan_bytes_matches_count(matches);
     else
-    {
-        result = (*found)->matches;
-        *count = (*found)->used;
-    }
+        result = 0;
 
     return result;
 
diff --git a/src/analysis/scan/context.h b/src/analysis/scan/context.h
index 916c618..75190ce 100644
--- a/src/analysis/scan/context.h
+++ b/src/analysis/scan/context.h
@@ -28,9 +28,12 @@
 #include <glib-object.h>
 
 
-#include "match.h"
+#include "matches.h"
 #include "options.h"
+#include "matches/area.h"
+#include "patterns/patid.h"
 #include "../content.h"
+#include "../../glibext/umemslice.h"
 
 
 
@@ -53,12 +56,6 @@ typedef struct _GScanContext GScanContext;
 typedef struct _GScanContextClass GScanContextClass;
 
 
-/* Identifiant de motif intégré */
-typedef uint64_t patid_t;
-
-#define INVALID_PATTERN_ID 0xffffffffffffffff
-
-
 /* Indique le type défini pour un contexte de suivi d'analyse. */
 GType g_scan_context_get_type(void);
 
@@ -68,11 +65,8 @@ GScanContext *g_scan_context_new(GScanOptions *);
 /* Fournit l'ensemble des options à respecter pour les analyses. */
 GScanOptions *g_scan_context_get_options(const GScanContext *);
 
-/* Fournit un identifiant unique pour un motif recherché. */
-patid_t g_scan_context_get_new_pattern_id(GScanContext *);
-
 /* Définit le contenu principal à analyser. */
-void g_scan_context_set_content(GScanContext *, GBinContent *);
+void g_scan_context_set_content(GScanContext *, GBinContent *, size_t);
 
 /* Fournit une référence au contenu principal analysé. */
 GBinContent *g_scan_context_get_content(const GScanContext *);
@@ -83,20 +77,20 @@ bool g_scan_context_is_scan_done(const GScanContext *);
 /* Note que la phase d'analyse de contenu est terminée. */
 void g_scan_context_mark_scan_as_done(GScanContext *);
 
-/* Enregistre une correspondance partielle dans un contenu. */
-void g_scan_context_register_atom_match(GScanContext *, patid_t, phys_t);
+/* Fournit la liste des allocateurs mémorisant des emplacements. */
+GUMemSlice **g_scan_context_get_match_storages(GScanContext *, size_t *);
 
 /* Retourne tous les correspondances partielles notées. */
-const phys_t *g_scan_context_get_atom_matches(const GScanContext *, patid_t, size_t *);
+GUMemSlice *g_scan_context_get_atom_matches(const GScanContext *, patid_t);
 
-/* Prépare les enregistrements de correspondances complètes. */
-void g_scan_context_prepare_full_match_registration(GScanContext *, GSearchPattern *, size_t);
+/* Enregistre toutes les correspondances établies pour un motif. */
+void g_scan_context_register_full_matches(GScanContext *, GSearchPattern *, GScanMatches *);
 
-/* Enregistre une correspondance complète avec un contenu. */
-void g_scan_context_register_full_match(GScanContext *, GScanMatch *);
+/* Fournit la liste de toutes les correspondances pour un motif. */
+GScanMatches *g_scan_context_get_full_matches(const GScanContext *, const GSearchPattern *);
 
-/* Fournit la liste de toutes les correspondances d'un motif. */
-const GScanMatch **g_scan_context_get_full_matches(const GScanContext *, const GSearchPattern *, size_t *);
+/* Dénombre les correspondances associées à un motif. */
+size_t g_scan_context_count_full_matches(const GScanContext *, const GSearchPattern *);
 
 /* Intègre une condition de correspondance pour règle. */
 bool g_scan_context_set_rule_condition(GScanContext *, const char *, GScanExpression *);
diff --git a/src/analysis/scan/exprs/handler.c b/src/analysis/scan/exprs/handler.c
index ecc5a21..d40d00f 100644
--- a/src/analysis/scan/exprs/handler.c
+++ b/src/analysis/scan/exprs/handler.c
@@ -268,6 +268,8 @@ ScanHandlerType g_scan_pattern_handler_get_handler_type(const GScanPatternHandle
 }
 
 
+#if 0   /* FIXME */
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : handler = instance à initialiser pleinement.                 *
@@ -323,6 +325,7 @@ GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *h
     return result;
 
 }
+#endif
 
 
 
@@ -425,7 +428,6 @@ static bool g_scan_pattern_handler_reduce_to_boolean(const GScanPatternHandler *
 static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *expr, GScanContext *ctx, size_t *count)
 {
     bool result;                            /* Bilan à retourner           */
-    size_t partial;                         /* Décompte partiel            */
     size_t i;                               /* Boucle de parcours          */
 
     result = true;
@@ -435,10 +437,7 @@ static bool g_scan_pattern_handler_count_items(const GScanPatternHandler *expr,
     *count = 0;
 
     for (i = 0; i < expr->count; i++)
-    {
-        g_scan_context_get_full_matches(ctx, expr->patterns[i], &partial);
-        *count += partial;
-    }
+        *count += g_scan_context_count_full_matches(ctx, expr->patterns[i]);
 
     return result;
 
@@ -465,11 +464,8 @@ static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, siz
     bool result;                            /* Bilan à retourner           */
     size_t i;                               /* Boucle de parcours          */
     size_t count;                           /* Quantité de correspondances */
-    const GScanMatch **matches;             /* Correspondances en place    */
-    const GScanBytesMatch *match;           /* Correspondance ciblée       */
-    phys_t start;                           /* Point de départ du motif    */
-    phys_t end;                             /* Point d'arrivée du motif    */
-    phys_t len;                             /* Taille du motif             */
+    GScanBytesMatches *matches;             /* Correspondances d'un motif  */
+    const match_area_t *area;               /* Zone de correspondance      */
     GBinContent *content;                   /* Contenu binaire à relire    */
     vmpa2t pos;                             /* Tête de lecture             */
     const bin_t *data;                      /* Accès aux données brutes    */
@@ -483,7 +479,7 @@ static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, siz
 
     for (i = 0; i < expr->count; i++)
     {
-        matches = g_scan_context_get_full_matches(ctx, expr->patterns[i], &count);
+        count = g_scan_context_count_full_matches(ctx, expr->patterns[i]);
 
         if (index < count)
             break;
@@ -494,51 +490,62 @@ static bool g_scan_pattern_handler_get_item(const GScanPatternHandler *expr, siz
 
     if (i == expr->count) goto done;
 
-    result = G_IS_SCAN_BYTES_MATCH(matches[index]);
-    if (!result) goto done;
+    /* Identification de la correspondance concernée */
 
-    match = G_SCAN_BYTES_MATCH(matches[index]);
+    matches = g_scan_context_get_full_matches(ctx, expr->patterns[i]);
+    if (matches == NULL) goto done;
 
-    /* Traitement adapté de la requête */
+    area = g_scan_bytes_matches_get(matches, index);
+    if (area == NULL) goto done_with_matches;
 
-    len = g_scan_bytes_match_get_location(match, &start, &end);
+    /* Traitement adapté de la requête */
 
     switch (expr->type)
     {
         case SHT_RAW:
-            content = g_scan_bytes_match_get_content(match);
+            content = g_scan_context_get_content(ctx);
 
-            init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
+            init_vmpa(&pos, area->start, VMPA_NO_VIRTUAL);
 
-            data = g_binary_content_get_raw_access(content, &pos, len);
+            data = g_binary_content_get_raw_access(content, &pos, area->end - area->start);
 
             binary.static_bin_data = data;
-            binary.len = len;
+            binary.len = area->end - area->start;
 
             *out = g_scan_literal_expression_new(LVT_STRING, &binary);
 
             g_object_unref(G_OBJECT(content));
+            result = true;
             break;
 
         case SHT_COUNTER:
             assert(false);
-            result = false;
             break;
 
         case SHT_START:
-            *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ start });
+            *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+                                                 (unsigned long long []){ area->start });
+            result = true;
             break;
 
         case SHT_LENGTH:
-            *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ len });
+            *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+                                                 (unsigned long long []){ area->end - area->start });
+            result = true;
             break;
 
         case SHT_END:
-            *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, (unsigned long long []){ end });
+            *out = g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER,
+                                                 (unsigned long long []){ area->end });
+            result = true;
             break;
 
     }
 
+ done_with_matches:
+
+    g_object_unref(G_OBJECT(matches));
+
  done:
 
     return result;
diff --git a/src/analysis/scan/exprs/handler.h b/src/analysis/scan/exprs/handler.h
index 24c4e8f..96e9301 100644
--- a/src/analysis/scan/exprs/handler.h
+++ b/src/analysis/scan/exprs/handler.h
@@ -65,9 +65,13 @@ GScanExpression *g_scan_pattern_handler_new(GSearchPattern ** const, size_t, Sca
 /* Indique le type de manipulation de correspondances spécifié. */
 ScanHandlerType g_scan_pattern_handler_get_handler_type(const GScanPatternHandler *);
 
+#if 0   /* FIXME */
+
 /* Fournit la liste de toutes les correspondances représentées. */
 GScanMatch **g_scan_pattern_handler_get_all_matches(const GScanPatternHandler *, GScanContext *, size_t *);
 
+#endif
+
 
 
 #endif  /* _ANALYSIS_SCAN_EXPRS_HANDLER_H */
diff --git a/src/analysis/scan/exprs/setcounter.c b/src/analysis/scan/exprs/setcounter.c
index 14e7676..da37746 100644
--- a/src/analysis/scan/exprs/setcounter.c
+++ b/src/analysis/scan/exprs/setcounter.c
@@ -319,6 +319,7 @@ static ScanReductionState g_scan_set_match_counter_reduce(const GScanSetMatchCou
     ScanReductionState result;              /* Etat synthétisé à retourner */
     size_t matched;                         /* Qté de motifs avec résultats*/
     size_t i;                               /* Boucle de parcours          */
+    GScanMatches *matches;                  /* Série de correspondances    */
     size_t count;                           /* Quantité de correspondances */
     bool status;                            /* Bilan d'évaluation finale   */
 
@@ -328,10 +329,18 @@ static ScanReductionState g_scan_set_match_counter_reduce(const GScanSetMatchCou
 
         for (i = 0; i < expr->count; i++)
         {
-            g_scan_context_get_full_matches(ctx, expr->patterns[i], &count);
+            matches = g_scan_context_get_full_matches(ctx, expr->patterns[i]);
 
-            if (count > 0)
-                matched++;
+            if (matches != NULL)
+            {
+                count = g_scan_matches_count(matches);
+
+                if (count > 0)
+                    matched++;
+
+                g_object_unref(G_OBJECT(matches));
+
+            }
 
         }
 
diff --git a/src/analysis/scan/items/modpath.c b/src/analysis/scan/items/modpath.c
index 1f4d779..62d3387 100644
--- a/src/analysis/scan/items/modpath.c
+++ b/src/analysis/scan/items/modpath.c
@@ -228,6 +228,11 @@ static char *g_scan_modpath_function_get_name(const GScanModpathFunction *item)
 
 static bool g_scan_modpath_function_run_call(GScanModpathFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
 {
+
+    return false;
+
+#if 0   /* FIXME */
+
     bool result;                            /* Bilan à retourner           */
     size_t i;                               /* Boucle de parcours #1       */
     size_t mcount;                          /* Quantité de correspondances */
@@ -296,4 +301,6 @@ static bool g_scan_modpath_function_run_call(GScanModpathFunction *item, GScanEx
 
     return result;
 
+#endif
+
 }
diff --git a/src/analysis/scan/match-int.h b/src/analysis/scan/match-int.h
deleted file mode 100644
index cf774c4..0000000
--- a/src/analysis/scan/match-int.h
+++ /dev/null
@@ -1,60 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * match-int.h - prototypes internes pour la sauvegarde d'une correspondance identifiée de motif
- *
- * Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef _ANALYSIS_SCAN_MATCH_INT_H
-#define _ANALYSIS_SCAN_MATCH_INT_H
-
-
-#include "match.h"
-
-
-
-/* Affiche une correspondance au format texte. */
-typedef void (* output_scan_match_to_text_fc) (const GScanMatch *, int);
-
-/* Affiche une correspondance au format JSON. */
-typedef void (* output_scan_match_to_json_fc) (const GScanMatch *, const sized_string_t *, unsigned int, int);
-
-
-/* Correspondance trouvée avec un motif (instance) */
-struct _GScanMatch
-{
-    GObject parent;                         /* A laisser en premier        */
-
-    GSearchPattern *source;                 /* Motif d'origine recherché   */
-
-};
-
-/* Correspondance trouvée avec un motif (classe) */
-struct _GScanMatchClass
-{
-    GObjectClass parent;                    /* A laisser en premier        */
-
-    output_scan_match_to_text_fc to_text;   /* Impression au format texte  */
-    output_scan_match_to_json_fc to_json;    /* Impression au format JSON   */
-
-};
-
-
-
-#endif  /* _ANALYSIS_SCAN_MATCH_INT_H */
diff --git a/src/analysis/scan/match.c b/src/analysis/scan/match.c
deleted file mode 100644
index b0b4320..0000000
--- a/src/analysis/scan/match.c
+++ /dev/null
@@ -1,263 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * match.c - sauvegarde d'une correspondance identifiée de motif
- *
- * Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
- */
-
-
-#include "match.h"
-
-
-#include "match-int.h"
-
-
-
-/* Initialise la classe des correspondances de motifs. */
-static void g_scan_match_class_init(GScanMatchClass *);
-
-/* Initialise une instance de correspondance de motif trouvée. */
-static void g_scan_match_init(GScanMatch *);
-
-/* Supprime toutes les références externes. */
-static void g_scan_match_dispose(GScanMatch *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_scan_match_finalize(GScanMatch *);
-
-
-
-/* Indique le type défini pour un correspondance de motif identifiée. */
-G_DEFINE_TYPE(GScanMatch, g_scan_match, G_TYPE_OBJECT);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : klass = classe à initialiser.                                *
-*                                                                             *
-*  Description : Initialise la classe des correspondances de motifs.          *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_match_class_init(GScanMatchClass *klass)
-{
-    GObjectClass *object;                   /* Autre version de la classe  */
-
-    object = G_OBJECT_CLASS(klass);
-
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_match_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_scan_match_finalize;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match = instance à initialiser.                              *
-*                                                                             *
-*  Description : Initialise une instance de correspondance de motif trouvée.  *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_match_init(GScanMatch *match)
-{
-    match->source = NULL;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match = instance d'objet GLib à traiter.                     *
-*                                                                             *
-*  Description : Supprime toutes les références externes.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_match_dispose(GScanMatch *match)
-{
-    g_clear_object(&match->source);
-
-    G_OBJECT_CLASS(g_scan_match_parent_class)->dispose(G_OBJECT(match));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match = instance d'objet GLib à traiter.                     *
-*                                                                             *
-*  Description : Procède à la libération totale de la mémoire.                *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_match_finalize(GScanMatch *match)
-{
-    G_OBJECT_CLASS(g_scan_match_parent_class)->finalize(G_OBJECT(match));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match = définition de correspondance à consulter.            *
-*                                                                             *
-*  Description : Indique la source du motif d'origine recherché.              *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-GSearchPattern *g_scan_match_get_source(const GScanMatch *match)
-{
-    GSearchPattern *result;                 /* Source à retourner          */
-
-    result = match->source;
-
-    g_object_ref(G_OBJECT(result));
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match = définition de correspondance à manipuler.            *
-*                fd    = canal d'écriture.                                    *
-*                                                                             *
-*  Description : Affiche une correspondance au format texte.                  *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_scan_match_output_to_text(const GScanMatch *match, int fd)
-{
-    GScanMatchClass *class;                 /* Classe à activer            */
-
-    class = G_SCAN_MATCH_GET_CLASS(match);
-
-    class->to_text(match, fd);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match = définition de correspondance à manipuler.            *
-*                                                                             *
-*  Description : Convertit une correspondance en texte.                       *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_scan_match_convert_as_text(const GScanMatch *match)
-{
-    /* TODO */
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match    = définition de correspondance à manipuler.         *
-*                padding  = éventuel bourrage initial à placer ou NULL.       *
-*                level    = profondeur actuelle.                              *
-*                fd       = canal d'écriture.                                 *
-*                trailing = impose une virgule finale ?                       *
-*                                                                             *
-*  Description : Affiche une correspondance au format JSON.                   *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_scan_match_output_to_json(const GScanMatch *match, const sized_string_t *padding, unsigned int level, int fd, bool trailing)
-{
-    unsigned int i;                         /* Boucle de parcours          */
-    GScanMatchClass *class;                 /* Classe à activer            */
-
-    /* Introduction */
-
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
-
-    write(fd, "{\n", 2);
-
-    /* Affichage du contenu */
-
-    class = G_SCAN_MATCH_GET_CLASS(match);
-
-    class->to_json(match, padding, level + 1, fd);
-
-    /* Conclusion */
-
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
-
-    if (trailing)
-        write(fd, "},\n", 3);
-    else
-        write(fd, "}\n", 2);
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : match = définition de correspondance à manipuler.            *
-*                                                                             *
-*  Description : Convertit une correspondance en JSON.                        *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-void g_scan_match_convert_as_json(const GScanMatch *match)
-{
-    /* TODO */
-
-}
diff --git a/src/analysis/scan/match.h b/src/analysis/scan/match.h
deleted file mode 100644
index e713b5d..0000000
--- a/src/analysis/scan/match.h
+++ /dev/null
@@ -1,71 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * match.h - prototypes pour la sauvegarde d'une correspondance identifiée de motif
- *
- * Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
- */
-
-
-#ifndef _ANALYSIS_SCAN_MATCH_H
-#define _ANALYSIS_SCAN_MATCH_H
-
-
-#include <glib-object.h>
-
-
-#include "pattern.h"
-#include "../../common/szstr.h"
-
-
-
-#define G_TYPE_SCAN_MATCH            g_scan_match_get_type()
-#define G_SCAN_MATCH(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATCH, GScanMatch))
-#define G_IS_SCAN_MATCH(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATCH))
-#define G_SCAN_MATCH_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATCH, GScanMatchClass))
-#define G_IS_SCAN_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATCH))
-#define G_SCAN_MATCH_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATCH, GScanMatchClass))
-
-
-/* Correspondance trouvée avec un motif (instance) */
-typedef struct _GScanMatch GScanMatch;
-
-/* Correspondance trouvée avec un motif (classe) */
-typedef struct _GScanMatchClass GScanMatchClass;
-
-
-/* Indique le type défini pour un correspondance de motif identifiée. */
-GType g_scan_match_get_type(void);
-
-/* Indique la source du motif d'origine recherché. */
-GSearchPattern *g_scan_match_get_source(const GScanMatch *);
-
-/* Affiche une correspondance au format texte. */
-void g_scan_match_output_to_text(const GScanMatch *, int);
-
-/* Convertit une correspondance en texte. */
-void g_scan_match_convert_as_text(const GScanMatch *);
-
-/* Affiche une correspondance au format JSON. */
-void g_scan_match_output_to_json(const GScanMatch *, const sized_string_t *, unsigned int, int, bool);
-
-/* Convertit une correspondance en JSON. */
-void g_scan_match_convert_as_json(const GScanMatch *);
-
-
-
-#endif  /* _ANALYSIS_SCAN_MATCH_H */
diff --git a/src/analysis/scan/matches-int.h b/src/analysis/scan/matches-int.h
new file mode 100644
index 0000000..674fe03
--- /dev/null
+++ b/src/analysis/scan/matches-int.h
@@ -0,0 +1,65 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * matches-int.h - prototypes internes pour la sauvegarde de correspondances de motif identifiées
+ *
+ * Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_INT_H
+#define _ANALYSIS_SCAN_MATCHES_INT_H
+
+
+#include "matches.h"
+
+
+
+/* Dénombre les correspondances enregistrées pour un motif. */
+typedef size_t (* count_scan_matches_fc) (const GScanMatches *);
+
+/* Affiche une série de correspondances au format texte. */
+typedef void (* output_scan_matches_to_text_fc) (const GScanMatches *, int);
+
+/* Affiche une série de correspondances au format JSON. */
+typedef void (* output_scan_matches_to_json_fc) (const GScanMatches *, const sized_string_t *, unsigned int, int);
+
+
+/* Correspondances trouvées avec un motif (instance) */
+struct _GScanMatches
+{
+    GObject parent;                         /* A laisser en premier        */
+
+    GSearchPattern *source;                 /* Motif d'origine recherché   */
+
+};
+
+/* Correspondances trouvées avec un motif (classe) */
+struct _GScanMatchesClass
+{
+    GObjectClass parent;                    /* A laisser en premier        */
+
+    count_scan_matches_fc count;            /* Décompte des correspondances*/
+
+    output_scan_matches_to_text_fc to_text; /* Impression au format texte  */
+    output_scan_matches_to_json_fc to_json; /* Impression au format JSON   */
+
+};
+
+
+
+#endif  /* _ANALYSIS_SCAN_MATCHES_INT_H */
diff --git a/src/analysis/scan/matches.c b/src/analysis/scan/matches.c
new file mode 100644
index 0000000..3dc15f9
--- /dev/null
+++ b/src/analysis/scan/matches.c
@@ -0,0 +1,268 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * matches.c - sauvegarde de correspondances de motif identifiées
+ *
+ * Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "matches.h"
+
+
+#include "matches-int.h"
+
+
+
+/* Initialise la classe des séries de correspondances de motifs. */
+static void g_scan_matches_class_init(GScanMatchesClass *);
+
+/* Initialise une instance de série de correspondances trouvées. */
+static void g_scan_matches_init(GScanMatches *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_matches_dispose(GScanMatches *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_matches_finalize(GScanMatches *);
+
+
+
+/* Indique le type défini pour une série de correspondances identifiées. */
+G_DEFINE_TYPE(GScanMatches, g_scan_matches, G_TYPE_OBJECT);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des séries de correspondances de motifs.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_matches_class_init(GScanMatchesClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_matches_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_matches_finalize;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = instance à initialiser.                            *
+*                                                                             *
+*  Description : Initialise une instance de série de correspondances trouvées.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_matches_init(GScanMatches *matches)
+{
+    matches->source = NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_matches_dispose(GScanMatches *matches)
+{
+    g_clear_object(&matches->source);
+
+    G_OBJECT_CLASS(g_scan_matches_parent_class)->dispose(G_OBJECT(matches));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = instance d'objet GLib à traiter.                   *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_matches_finalize(GScanMatches *matches)
+{
+    G_OBJECT_CLASS(g_scan_matches_parent_class)->finalize(G_OBJECT(matches));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = définition de correspondance à consulter.          *
+*                                                                             *
+*  Description : Indique la source du motif d'origine recherché.              *
+*                                                                             *
+*  Retour      : Motif à l'origine des correspondances.                       *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GSearchPattern *g_scan_matches_get_source(const GScanMatches *matches)
+{
+    GSearchPattern *result;                 /* Source à retourner          */
+
+    result = matches->source;
+
+    g_object_ref(G_OBJECT(result));
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = définition de correspondance à consulter.          *
+*                                                                             *
+*  Description : Dénombre les correspondances enregistrées pour un motif.     *
+*                                                                             *
+*  Retour      : Quantité de correspondances établies.                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_scan_matches_count(const GScanMatches *matches)
+{
+    size_t result;                          /* Quantité à retourner        */
+    GScanMatchesClass *class;               /* Classe à activer            */
+
+    class = G_SCAN_MATCHES_GET_CLASS(matches);
+
+    result = class->count(matches);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = définition de correspondance à manipuler.          *
+*                fd      = canal d'écriture.                                  *
+*                                                                             *
+*  Description : Affiche une série de correspondances au format texte.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_matches_output_to_text(const GScanMatches *matches, int fd)
+{
+    GScanMatchesClass *class;               /* Classe à activer            */
+
+    class = G_SCAN_MATCHES_GET_CLASS(matches);
+
+    class->to_text(matches, fd);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = définition de correspondance à manipuler.          *
+*                                                                             *
+*  Description : Convertit une série de correspondances en texte.             *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_matches_convert_as_text(const GScanMatches *matches)
+{
+    /* TODO */
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches  = définition de correspondance à manipuler.         *
+*                padding  = éventuel bourrage initial à placer ou NULL.       *
+*                level    = profondeur actuelle.                              *
+*                fd       = canal d'écriture.                                 *
+*                                                                             *
+*  Description : Affiche une série de correspondances au format JSON.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_matches_output_to_json(const GScanMatches *matches, const sized_string_t *padding, unsigned int level, int fd)
+{
+    GScanMatchesClass *class;               /* Classe à activer            */
+
+    class = G_SCAN_MATCHES_GET_CLASS(matches);
+
+    class->to_json(matches, padding, level + 1, fd);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = définition de correspondance à manipuler.          *
+*                                                                             *
+*  Description : Convertit une série de correspondances en JSON.              *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_matches_convert_as_json(const GScanMatches *matches)
+{
+    /* TODO */
+
+}
diff --git a/src/analysis/scan/matches.h b/src/analysis/scan/matches.h
new file mode 100644
index 0000000..345db96
--- /dev/null
+++ b/src/analysis/scan/matches.h
@@ -0,0 +1,74 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * matches.h - prototypes pour la sauvegarde de correspondances de motif identifiées
+ *
+ * Copyright (C) 2022 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_H
+#define _ANALYSIS_SCAN_MATCHES_H
+
+
+#include <glib-object.h>
+
+
+#include "pattern.h"
+#include "../../common/szstr.h"
+
+
+
+#define G_TYPE_SCAN_MATCHES            g_scan_matches_get_type()
+#define G_SCAN_MATCHES(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATCHES, GScanMatches))
+#define G_IS_SCAN_MATCHES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATCHES))
+#define G_SCAN_MATCHES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATCHES, GScanMatchesClass))
+#define G_IS_SCAN_MATCHES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATCHES))
+#define G_SCAN_MATCHES_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATCHES, GScanMatchesClass))
+
+
+/* Correspondances trouvées avec un motif (instance) */
+typedef struct _GScanMatches GScanMatches;
+
+/* Correspondances trouvées avec un motif (classe) */
+typedef struct _GScanMatchesClass GScanMatchesClass;
+
+
+/* Indique le type défini pour une série de correspondances identifiées. */
+GType g_scan_matches_get_type(void);
+
+/* Indique la source du motif d'origine recherché. */
+GSearchPattern *g_scan_matches_get_source(const GScanMatches *);
+
+/* Dénombre les correspondances enregistrées pour un motif. */
+size_t g_scan_matches_count(const GScanMatches *);
+
+/* Affiche une série de correspondances au format texte. */
+void g_scan_matches_output_to_text(const GScanMatches *, int);
+
+/* Convertit une série de correspondances en texte. */
+void g_scan_matches_convert_as_text(const GScanMatches *);
+
+/* Affiche une série de correspondances au format JSON. */
+void g_scan_matches_output_to_json(const GScanMatches *, const sized_string_t *, unsigned int, int);
+
+/* Convertit une série de correspondances en JSON. */
+void g_scan_matches_convert_as_json(const GScanMatches *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_MATCHES_H */
diff --git a/src/analysis/scan/matches/Makefile.am b/src/analysis/scan/matches/Makefile.am
index d6b51c6..f1a69c3 100644
--- a/src/analysis/scan/matches/Makefile.am
+++ b/src/analysis/scan/matches/Makefile.am
@@ -3,9 +3,9 @@ noinst_LTLIBRARIES  = libanalysisscanmatches.la
 
 
 libanalysisscanmatches_la_SOURCES =		\
+	area.h area.c						\
 	bytes-int.h							\
-	bytes.h bytes.c						\
-	pending.h pending.c
+	bytes.h bytes.c
 
 libanalysisscanmatches_la_CFLAGS = $(LIBGOBJ_CFLAGS)
 
diff --git a/src/analysis/scan/matches/area.c b/src/analysis/scan/matches/area.c
new file mode 100644
index 0000000..3f512b0
--- /dev/null
+++ b/src/analysis/scan/matches/area.c
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * area.c - conservation des localisations de correspondances
+ *
+ * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#include "area.h"
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = première zone de correspondance à comparer.              *
+*                b = seconde zone de correspondance à comparer.               *
+*                                                                             *
+*  Description : Etablit une comparaison entre deux zones de correspondance.  *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+int compare_match_area_as_dl_item(const dl_list_item *a, const dl_list_item *b)
+{
+    int result;                             /* Bilan à retourner           */
+    match_area_t *area_a;                   /* Première zone à traiter     */
+    match_area_t *area_b;                   /* Seconde zone à traiter      */
+
+    area_a = match_area_from_item(a);
+    area_b = match_area_from_item(b);
+
+    result = sort_uint64_t(area_a->start, area_b->start);
+
+    if (result == 0)
+        result = sort_uint64_t(area_a->end, area_b->end);
+
+    return result;
+
+}
diff --git a/src/analysis/scan/matches/area.h b/src/analysis/scan/matches/area.h
new file mode 100644
index 0000000..b059b35
--- /dev/null
+++ b/src/analysis/scan/matches/area.h
@@ -0,0 +1,85 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * area.h - prototypes pour la conservation des localisations de correspondances
+ *
+ * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_MATCHES_AREA_H
+#define _ANALYSIS_SCAN_MATCHES_AREA_H
+
+
+#include <assert.h>
+
+
+#include "../../../arch/vmpa.h"
+#include "../../../common/dllist.h"
+
+
+
+/* Couverture d'une correspondance */
+typedef struct _match_area_t
+{
+    phys_t start;                           /* Point de départ             */
+    phys_t end;                             /* Point d'arrivée (exclus)    */
+
+    DL_LIST_ITEM(link);                     /* Lien vers les maillons      */
+
+    size_t mod_path_index;                  /* Indice de construction      */
+    bool has_mod_path;                      /* Validité du champ précédent */
+
+} match_area_t;
+
+
+#define match_area_from_item(item) \
+    (match_area_t *)container_of(item, match_area_t, link)
+
+#define add_tail_match_area(new, head) \
+    dl_list_add_tail(new, head, match_area_t, link)
+
+#define del_match_area(item, head) \
+    dl_list_del(item, head, match_area_t, link)
+
+#define for_each_match_area(pos, head) \
+    dl_list_for_each(pos, head, match_area_t, link)
+
+#define for_each_match_area_safe(pos, head, next) \
+    dl_list_for_each_safe(pos, head, next, match_area_t, link)
+
+#define is_last_match_area(item, head) \
+    dl_list_is_last(item, head, link)
+
+#define merge_match_areas(head1, head2) \
+    dl_list_merge(head1, head2, match_area_t, link)
+
+#define sort_match_areas_no_dup(head, len, cmp, dup)    \
+    ({                                                  \
+        assert(!dl_list_empty(*(head)));                \
+        dl_list_item *hmbr = &(*head)->link;            \
+        sort_dl_list_no_dup(&hmbr, len, cmp, dup);      \
+        match_area_from_item(hmbr);                     \
+    })
+
+
+/* Etablit une comparaison entre deux zones de correspondance. */
+int compare_match_area_as_dl_item(const dl_list_item *, const dl_list_item *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_MATCHES_AREA_H */
diff --git a/src/analysis/scan/matches/bytes-int.h b/src/analysis/scan/matches/bytes-int.h
index f57cb9f..d356208 100644
--- a/src/analysis/scan/matches/bytes-int.h
+++ b/src/analysis/scan/matches/bytes-int.h
@@ -1,6 +1,6 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * bytes-int.h - prototypes internes pour la sauvegarde d'une correspondance identifiée de suite d'octets
+ * bytes-int.h - prototypes internes pour la sauvegarde de correspondances avec des suites d'octets identifiées
  *
  * Copyright (C) 2022 Cyrille Bagard
  *
@@ -28,35 +28,36 @@
 #include "bytes.h"
 
 
-#include "../match-int.h"
+#include "../matches-int.h"
 
 
 
-/* Correspondance trouvée avec une chaîne (instance) */
-struct _GScanBytesMatch
+/* Correspondances trouvées avec des suite d'octets (instance) */
+struct _GScanBytesMatches
 {
-    GScanMatch parent;                      /* A laisser en premier        */
+    GScanMatches parent;                    /* A laisser en premier        */
 
-    GBinContent *content;                   /* Contenu binaire de référence*/
+    GScanContext *context;                  /* Contexte de rattachement    */
 
-    phys_t start;                           /* Début du motif représenté   */
-    phys_t len;                             /* Taille du motif représenté  */
+    // TODO : if NDEBUG ?
+    phys_t content_start;                   /* Point de début du contenu   */
+    phys_t content_end;                     /* Point de fin du contenu     */
 
-    size_t mod_path_index;                  /* Indice de construction      */
-    bool has_mod_path;                      /* Validité du champ précédent */
+    match_area_t *areas;                    /* Zones couvertes             */
+    size_t count;                           /* Nombre de zones             */
 
 };
 
-/* Correspondance trouvée avec une chaîne (classe) */
-struct _GScanBytesMatchClass
+/* Correspondances trouvées avec des suite d'octets (classe) */
+struct _GScanBytesMatchesClass
 {
-    GScanMatchClass parent;                 /* A laisser en premier        */
+    GScanMatchesClass parent;               /* A laisser en premier        */
 
 };
 
 
-/* Met en place une correspondance trouvée avec un motif. */
-bool g_scan_bytes_match_create(GScanBytesMatch *, GSearchPattern *, GBinContent *, phys_t, phys_t);
+/* Met en place une série de correspondances avec des octets. */
+bool g_scan_bytes_matches_create(GScanBytesMatches *, GSearchPattern *, GScanContext *);
 
 
 
diff --git a/src/analysis/scan/matches/bytes.c b/src/analysis/scan/matches/bytes.c
index f0b97fe..ca8c5b6 100644
--- a/src/analysis/scan/matches/bytes.c
+++ b/src/analysis/scan/matches/bytes.c
@@ -36,20 +36,20 @@
 
 
 
-/* --------------------- CORRESPONDANCE AVEC UNE SUITE D'OCTETS --------------------- */
+/* -------------------- CONSERVATION DE CORRESPONDANCES ETABLIES -------------------- */
 
 
-/* Initialise la classe des correspondances de chaînes. */
-static void g_scan_bytes_match_class_init(GScanBytesMatchClass *);
+/* Initialise la classe des séries de correspondances d'octets. */
+static void g_scan_bytes_matches_class_init(GScanBytesMatchesClass *);
 
-/* Initialise une instance de correspondance de chaîne trouvée. */
-static void g_scan_bytes_match_init(GScanBytesMatch *);
+/* Initialise une instance de série de correspondances trouvées. */
+static void g_scan_bytes_matches_init(GScanBytesMatches *);
 
 /* Supprime toutes les références externes. */
-static void g_scan_bytes_match_dispose(GScanBytesMatch *);
+static void g_scan_bytes_matches_dispose(GScanBytesMatches *);
 
 /* Procède à la libération totale de la mémoire. */
-static void g_scan_bytes_match_finalize(GScanBytesMatch *);
+static void g_scan_bytes_matches_finalize(GScanBytesMatches *);
 
 
 
@@ -57,27 +57,27 @@ static void g_scan_bytes_match_finalize(GScanBytesMatch *);
 
 
 /* Affiche une correspondance au format texte. */
-static void g_scan_bytes_match_output_to_text(const GScanBytesMatch *, int);
+static void g_scan_bytes_matches_output_to_text(const GScanBytesMatches *, int);
 
 /* Affiche une correspondance au format JSON. */
-static void g_scan_bytes_match_output_to_json(const GScanBytesMatch *, const sized_string_t *, unsigned int, int);
+static void g_scan_bytes_matches_output_to_json(const GScanBytesMatches *, const sized_string_t *, unsigned int, int);
 
 
 
 /* ---------------------------------------------------------------------------------- */
-/*                       CORRESPONDANCE AVEC UNE SUITE D'OCTETS                       */
+/*                      CONSERVATION DE CORRESPONDANCES ETABLIES                      */
 /* ---------------------------------------------------------------------------------- */
 
 
-/* Indique le type défini pour un correspondance de chaîne identifiée. */
-G_DEFINE_TYPE(GScanBytesMatch, g_scan_bytes_match, G_TYPE_SCAN_MATCH);
+/* Indique le type défini pour une série de correspondances d'octets identifiées. */
+G_DEFINE_TYPE(GScanBytesMatches, g_scan_bytes_matches, G_TYPE_SCAN_MATCHES);
 
 
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : klass = classe à initialiser.                                *
 *                                                                             *
-*  Description : Initialise la classe des correspondances de chaînes.         *
+*  Description : Initialise la classe des séries de correspondances d'octets. *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -85,29 +85,29 @@ G_DEFINE_TYPE(GScanBytesMatch, g_scan_bytes_match, G_TYPE_SCAN_MATCH);
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_bytes_match_class_init(GScanBytesMatchClass *klass)
+static void g_scan_bytes_matches_class_init(GScanBytesMatchesClass *klass)
 {
     GObjectClass *object;                   /* Autre version de la classe  */
-    GScanMatchClass *match;                 /* Version parente de la classe*/
+    GScanMatchesClass *matches;             /* Version parente de la classe*/
 
     object = G_OBJECT_CLASS(klass);
 
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_bytes_match_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_scan_bytes_match_finalize;
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_bytes_matches_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_bytes_matches_finalize;
 
-    match = G_SCAN_MATCH_CLASS(klass);
+    matches = G_SCAN_MATCHES_CLASS(klass);
 
-    match->to_text = (output_scan_match_to_text_fc)g_scan_bytes_match_output_to_text;
-    match->to_json = (output_scan_match_to_json_fc)g_scan_bytes_match_output_to_json;
+    matches->to_text = (output_scan_matches_to_text_fc)g_scan_bytes_matches_output_to_text;
+    matches->to_json = (output_scan_matches_to_json_fc)g_scan_bytes_matches_output_to_json;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = instance à initialiser.                              *
+*  Paramètres  : matches = instance à initialiser.                            *
 *                                                                             *
-*  Description : Initialise une instance de correspondance de chaîne trouvée. *
+*  Description : Initialise une instance de série de correspondances trouvées.*
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -115,21 +115,22 @@ static void g_scan_bytes_match_class_init(GScanBytesMatchClass *klass)
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_bytes_match_init(GScanBytesMatch *match)
+static void g_scan_bytes_matches_init(GScanBytesMatches *matches)
 {
-    match->content = NULL;
+    matches->context = NULL;
 
-    match->start = VMPA_NO_PHYSICAL;
-    match->len = VMPA_NO_PHYSICAL;
+    matches->content_start = VMPA_NO_PHYSICAL;
+    matches->content_end = VMPA_NO_PHYSICAL;
 
-    match->has_mod_path = false;
+    matches->areas = NULL;
+    matches->count = 0;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = instance d'objet GLib à traiter.                     *
+*  Paramètres  : matches = instance d'objet GLib à traiter.                   *
 *                                                                             *
 *  Description : Supprime toutes les références externes.                     *
 *                                                                             *
@@ -139,18 +140,18 @@ static void g_scan_bytes_match_init(GScanBytesMatch *match)
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_bytes_match_dispose(GScanBytesMatch *match)
+static void g_scan_bytes_matches_dispose(GScanBytesMatches *matches)
 {
-    g_clear_object(&match->content);
+    //g_clear_object(&matches->context);
 
-    G_OBJECT_CLASS(g_scan_bytes_match_parent_class)->dispose(G_OBJECT(match));
+    G_OBJECT_CLASS(g_scan_bytes_matches_parent_class)->dispose(G_OBJECT(matches));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = instance d'objet GLib à traiter.                     *
+*  Paramètres  : matches = instance d'objet GLib à traiter.                   *
 *                                                                             *
 *  Description : Procède à la libération totale de la mémoire.                *
 *                                                                             *
@@ -160,9 +161,9 @@ static void g_scan_bytes_match_dispose(GScanBytesMatch *match)
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_bytes_match_finalize(GScanBytesMatch *match)
+static void g_scan_bytes_matches_finalize(GScanBytesMatches *matches)
 {
-    G_OBJECT_CLASS(g_scan_bytes_match_parent_class)->finalize(G_OBJECT(match));
+    G_OBJECT_CLASS(g_scan_bytes_matches_parent_class)->finalize(G_OBJECT(matches));
 
 }
 
@@ -170,11 +171,9 @@ static void g_scan_bytes_match_finalize(GScanBytesMatch *match)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : source  = lien vers le motif recherché d'origine.            *
-*                content = contenu binaire présentant un motif reconnu.       *
-*                start   = position de départ d'un motif détecté.             *
-*                len     = taille du motif repéré.                            *
+*                context = contexte associé au scan courant.                  *
 *                                                                             *
-*  Description : Prend note d'une correspondance trouvée avec un motif.       *
+*  Description : Crée un suivi pour série de correspondances avec des octets. *
 *                                                                             *
 *  Retour      : Correspondance mise en place.                                *
 *                                                                             *
@@ -182,13 +181,13 @@ static void g_scan_bytes_match_finalize(GScanBytesMatch *match)
 *                                                                             *
 ******************************************************************************/
 
-GScanMatch *g_scan_bytes_match_new(GSearchPattern *source, GBinContent *content, phys_t start, phys_t len)
+GScanMatches *g_scan_bytes_matches_new(GSearchPattern *source, GScanContext *context)
 {
-    GScanMatch *result;                     /* Structure à retourner       */
+    GScanMatches *result;                   /* Structure à retourner       */
 
-    result = g_object_new(G_TYPE_SCAN_BYTES_MATCH, NULL);
+    result = g_object_new(G_TYPE_SCAN_BYTES_MATCHES, NULL);
 
-    if (!g_scan_bytes_match_create(G_SCAN_BYTES_MATCH(result), source, content, start, len))
+    if (!g_scan_bytes_matches_create(G_SCAN_BYTES_MATCHES(result), source, context))
         g_clear_object(&result);
 
     return result;
@@ -198,13 +197,11 @@ GScanMatch *g_scan_bytes_match_new(GSearchPattern *source, GBinContent *content,
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match   = instance à initialiser pleinement.                 *
+*  Paramètres  : matches = instance à initialiser pleinement.                 *
 *                source  = lien vers le motif recherché d'origine.            *
-*                content = contenu binaire présentant un motif reconnu.       *
-*                start   = position de départ d'un motif détecté.             *
-*                len     = taille du motif repéré.                            *
+*                context = contexte associé au scan courant.                  *
 *                                                                             *
-*  Description : Met en place une correspondance trouvée avec un motif.       *
+*  Description : Met en place une série de correspondances avec des octets.   *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -212,23 +209,33 @@ GScanMatch *g_scan_bytes_match_new(GSearchPattern *source, GBinContent *content,
 *                                                                             *
 ******************************************************************************/
 
-bool g_scan_bytes_match_create(GScanBytesMatch *match, GSearchPattern *source, GBinContent *content, phys_t start, phys_t len)
+bool g_scan_bytes_matches_create(GScanBytesMatches *matches, GSearchPattern *source, GScanContext *context)
 {
     bool result;                            /* Bilan à retourner           */
-    GScanMatch *base;                       /* Lien vers les infos de base */
+    GScanMatches *base;                     /* Lien vers les infos de base */
+    GBinContent *content;                   /* Contenu à manipuler         */
+    vmpa2t start;                           /* Point de début du contenu   */
+    vmpa2t end;                             /* Point de fin du contenu     */
 
     result = true;
 
-    base = G_SCAN_MATCH(match);
+    base = G_SCAN_MATCHES(matches);
 
     base->source = source;
     g_object_ref(G_OBJECT(source));
 
-    match->content = content;
-    g_object_ref(G_OBJECT(content));
+    matches->context = context;
+    //g_object_ref(G_OBJECT(context));
 
-    match->start = start;
-    match->len = len;
+    content = g_scan_context_get_content(context);
+
+    g_binary_content_compute_start_pos(content, &start);
+    g_binary_content_compute_end_pos(content, &end);
+
+    matches->content_start = start.physical;
+    matches->content_end = end.physical;
+
+    g_object_unref(G_OBJECT(content));
 
     return result;
 
@@ -237,21 +244,21 @@ bool g_scan_bytes_match_create(GScanBytesMatch *match, GSearchPattern *source, G
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = informations de correspondance à consulter.          *
+*  Paramètres  : matches = informations de correspondances à consulter.       *
 *                                                                             *
-*  Description : Fournit une référence au contenu lié à la correspondance.    *
+*  Description : Fournit le contexte du scan associé aux correspondances.     *
 *                                                                             *
-*  Retour      : Content binaire associé au context.                          *
+*  Retour      : Contexte de scan courant.                                    *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-GBinContent *g_scan_bytes_match_get_content(const GScanBytesMatch *match)
+GScanContext *g_scan_bytes_matches_get_context(const GScanBytesMatches *matches)
 {
-    GBinContent *result;                    /* Instance à retourner        */
+    GScanContext *result;                   /* Instance à retourner        */
 
-    result = match->content;
+    result = matches->context;
 
     g_object_ref(G_OBJECT(result));
 
@@ -262,26 +269,44 @@ GBinContent *g_scan_bytes_match_get_content(const GScanBytesMatch *match)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = informations de correspondance à consulter.          *
-*                start = position de départ d'un motif détecté. [OUT]         *
-*                end   = position d'arrivée d'un motif détecté. [OUT]         *
+*  Paramètres  : matches = suivi de correspondances à manipuler.              *
+*                list    = correspondances établies à mémoriser.              *
+*                count   = taille de cette liste.                             *
 *                                                                             *
-*  Description : Indique la localisation d'une correspondance établie.        *
+*  Description : Intègre une liste de correspondances vérifiées.              *
 *                                                                             *
-*  Retour      : Taille mesurée de la correspondance.                         *
+*  Retour      : -                                                            *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-phys_t g_scan_bytes_match_get_location(const GScanBytesMatch *match, phys_t *start, phys_t *end)
+void g_scan_bytes_matches_set_list(GScanBytesMatches *matches, match_area_t *list, size_t count)
 {
-    phys_t result;                          /* Taille à retourner          */
+    matches->areas = list;
 
-    result = match->len;
+    matches->count = count;
 
-    *start = match->start;
-    *end = match->start + result;
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = suivi de correspondances à consulter.              *
+*                                                                             *
+*  Description : Indique le nombre de correspondances pour une définition.    *
+*                                                                             *
+*  Retour      : Quantité de correspondances établies pour un motif entier.   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_scan_bytes_matches_count(const GScanBytesMatches *matches)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    result = matches->count;
 
     return result;
 
@@ -290,28 +315,71 @@ phys_t g_scan_bytes_match_get_location(const GScanBytesMatch *match, phys_t *sta
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = informations de correspondance à compléter.          *
-*                index = indice de la combinaison de modificateurs ciblée.    *
+*  Paramètres  : matches = suivi de correspondances à consulter.              *
+*                index   = indice de la correspondance recherchée.            *
 *                                                                             *
-*  Description : Mémorise l'origine d'une correspondance à partir d'un indice.*
+*  Description : Fournit les informations relatives à une correspondance.     *
 *                                                                             *
-*  Retour      : -                                                            *
+*  Retour      : Propritétés de la correspondance visée ou NULL pour un échec.*
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const match_area_t *g_scan_bytes_matches_get(const GScanBytesMatches *matches, size_t index)
+{
+    const match_area_t *result;             /* Pointeur à retourner        */
+
+
+    for_each_match_area(result, matches->areas)
+    {
+        if (index == 0)
+            break;
+    }
+
+    assert(index == 0);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = informations de correspondance à consulter.        *
+*                index   = indice de la correspondance visée.                 *
+*                start   = position de départ d'un motif détecté. [OUT]       *
+*                end     = position d'arrivée d'un motif détecté. [OUT]       *
+*                                                                             *
+*  Description : Indique la localisation d'une correspondance établie.        *
+*                                                                             *
+*  Retour      : Taille mesurée de la correspondance.                         *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_bytes_match_remember_modifier_path(GScanBytesMatch *match, size_t index)
+phys_t g_scan_bytes_matches_get_location(const GScanBytesMatches *matches, size_t index, phys_t *start, phys_t *end)
 {
-    match->mod_path_index = index;
-    match->has_mod_path = true;
+    phys_t result;                          /* Taille à retourner          */
+
+    result = 0;
+
+    /*
+    result = match->len;
+
+    *start = match->start;
+    *end = match->start + result;
+    */
+
+    return result;
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = informations de correspondance à consulter.          *
+*  Paramètres  : matches = informations de correspondance à consulter.        *
 *                                                                             *
 *  Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
 *                                                                             *
@@ -321,11 +389,15 @@ void g_scan_bytes_match_remember_modifier_path(GScanBytesMatch *match, size_t in
 *                                                                             *
 ******************************************************************************/
 
-char *g_scan_bytes_match_get_modifier_path(const GScanBytesMatch *match)
+char *g_scan_bytes_matches_get_modifier_path(const GScanBytesMatches *matches)
 {
     char *result;                           /* Combinaison à retourner     */
     GBytesToken *pattern;                   /* Autre version du motif      */
 
+    result = NULL;
+
+    /*
+
     if (match->has_mod_path)
     {
         pattern = G_BYTES_TOKEN(G_SCAN_MATCH(match)->source);
@@ -334,6 +406,7 @@ char *g_scan_bytes_match_get_modifier_path(const GScanBytesMatch *match)
 
     else
         result = NULL;
+    */
 
     return result;
 
@@ -348,8 +421,8 @@ char *g_scan_bytes_match_get_modifier_path(const GScanBytesMatch *match)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match = définition de correspondance à manipuler.            *
-*                fd    = canal d'écriture.                                    *
+*  Paramètres  : matches = définition de correspondance à manipuler.          *
+*                fd      = canal d'écriture.                                  *
 *                                                                             *
 *  Description : Affiche une correspondance au format texte.                  *
 *                                                                             *
@@ -359,91 +432,105 @@ char *g_scan_bytes_match_get_modifier_path(const GScanBytesMatch *match)
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_bytes_match_output_to_text(const GScanBytesMatch *match, int fd)
+static void g_scan_bytes_matches_output_to_text(const GScanBytesMatches *matches, int fd)
 {
+    GBinContent *content;                   /* Contenu binaire analysé     */
+    GScanMatches *base;                     /* Lien vers les infos de base */
+    const char *name;                       /* Désignation du motif ciblé  */
+    match_area_t *iter;                     /* Boucle de parcours #1       */
     char value[2 + ULLONG_MAXLEN];          /* Impression de la position   */
     int ret;                                /* Bilan d'une conversion      */
-    GScanMatch *base;                       /* Lien vers les infos de base */
-    const char *name;                       /* Désignation du motif ciblé  */
     vmpa2t pos;                             /* Tête de lecture             */
+    phys_t len;                             /* Taille d'une correspondance */
     const bin_t *data;                      /* Accès aux données brutes    */
     phys_t k;                               /* Boucle de parcours #2       */
 
-    /* Position dans le binaire (hexadécimal) */
+    content = g_scan_context_get_content(matches->context);
 
-    ret = snprintf(value, ULLONG_MAXLEN, "0x%llx", (unsigned long long)match->start);
+    base = G_SCAN_MATCHES(matches);
 
-    if (ret > 0)
-        write(fd, value, ret);
+    name = g_search_pattern_get_name(base->source);
 
-    else
+    for_each_match_area(iter, matches->areas)
     {
-        log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!");
-        write(fd, "\"<error>\"", 9);
-    }
-
-    write(fd, ":", 1);
+        /* Position dans le binaire (hexadécimal) */
 
-    /* Affichage de la désignation */
+        ret = snprintf(value, ULLONG_MAXLEN, "0x%llx", (unsigned long long)iter->start);
 
-    write(fd, "$", 1);
+        if (ret > 0)
+            write(fd, value, ret);
 
-    base = G_SCAN_MATCH(match);
+        else
+        {
+            log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!");
+            write(fd, "\"<error>\"", 9);
+        }
 
-    name = g_search_pattern_get_name(base->source);
+        write(fd, ":", 1);
 
-    /**
-     * Les fonctionnalités Yara d'origine autorisent les variables anonymes '$'.
-     *
-     * Cette absence de nom est supportée ici.
-     */
+        /* Affichage de la désignation */
 
-    if (name != NULL)
-        write(fd, name, strlen(name));
+        write(fd, "$", 1);
 
-    write(fd, ": ", 2);
+        /**
+         * Les fonctionnalités Yara d'origine autorisent les variables anonymes '$'.
+         *
+         * Cette absence de nom est supportée ici.
+         */
 
-    /* Affichage du contenu */
+        if (name != NULL)
+            write(fd, name, strlen(name));
 
-    init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL);
+        write(fd, ": ", 2);
 
-    data = g_binary_content_get_raw_access(match->content, &pos, match->len);
+        /* Affichage du contenu */
 
-    for (k = 0; k < match->len; k++)
-    {
-        if (isprint(data[k]))
-            write(fd, &data[k], 1);
+        init_vmpa(&pos, iter->start, VMPA_NO_VIRTUAL);
 
-        else
-        {
-            write(fd, "\\x", 2);
+        len = iter->end - iter->start;
 
-            ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]);
+        data = g_binary_content_get_raw_access(content, &pos, len);
+        assert(data != NULL);
 
-            if (ret > 0)
-            {
-                assert(ret == 2);
-                write(fd, value, ret);
-            }
+        for (k = 0; k < len; k++)
+        {
+            if (isprint(data[k]))
+                write(fd, &data[k], 1);
 
             else
             {
-                log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
-                write(fd, "??", 2);
+                write(fd, "\\x", 2);
+
+                ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]);
+
+                if (ret > 0)
+                {
+                    assert(ret == 2);
+                    write(fd, value, ret);
+                }
+
+                else
+                {
+                    log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+                    write(fd, "??", 2);
+                }
+
             }
 
         }
 
+        write(fd, "\n", 1);
+
     }
 
-    write(fd, "\n", 1);
+    g_object_unref(G_OBJECT(content));
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : match   = définition de correspondance à manipuler.          *
+*  Paramètres  : matches = définition de correspondance à manipuler.          *
 *                padding = éventuel bourrage initial à placer ou NULL.        *
 *                level   = profondeur actuelle.                               *
 *                fd      = canal d'écriture.                                  *
@@ -456,188 +543,246 @@ static void g_scan_bytes_match_output_to_text(const GScanBytesMatch *match, int
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_bytes_match_output_to_json(const GScanBytesMatch *match, const sized_string_t *padding, unsigned int level, int fd)
+static void g_scan_bytes_matches_output_to_json(const GScanBytesMatches *matches, const sized_string_t *padding, unsigned int level, int fd)
 {
     unsigned int i;                         /* Boucle de parcours #1       */
-    vmpa2t pos;                             /* Tête de lecture             */
     char value[4 + ULLONG_MAXLEN];          /* Impression de la position   */
     int ret;                                /* Bilan d'une conversion      */
+    GBinContent *content;                   /* Contenu binaire analysé     */
+    match_area_t *iter;                     /* Boucle de parcours #1       */
+    vmpa2t pos;                             /* Tête de lecture             */
+    phys_t len;                             /* Taille d'une correspondance */
     const bin_t *data;                      /* Accès aux données brutes    */
     phys_t k;                               /* Boucle de parcours #2       */
 
-    /* Position dans le binaire (décimal) */
+    /* Nombre de correspondances */
 
     for (i = 0; i < level; i++)
         write(fd, padding->data, padding->len);
 
-    write(fd, "\"offset\": ", 10);
+    write(fd, "\"match_count\": ", 15);
 
-    ret = snprintf(value, ULLONG_MAXLEN, "%llu", (unsigned long long)match->start);
+    ret = snprintf(value, ULLONG_MAXLEN, "%zu", matches->count);
 
     if (ret > 0)
         write(fd, value, ret);
 
     else
     {
-        log_simple_message(LMT_EXT_ERROR, "Error while converting offset!");
+        log_simple_message(LMT_EXT_ERROR, "Error while converting value!");
         write(fd, "null", 4);
     }
 
     write(fd, ",\n", 2);
 
-    /* Position dans le binaire (hexadécimal) */
+    /* Détail des correspondances */
 
     for (i = 0; i < level; i++)
         write(fd, padding->data, padding->len);
 
-    write(fd, "\"offset_hex\": ", 14);
+    write(fd, "\"matches\": [\n", 13);
 
-    ret = snprintf(value, ULLONG_MAXLEN, "\"0x%llx\"", (unsigned long long)match->start);
+    content = g_scan_context_get_content(matches->context);
 
-    if (ret > 0)
-        write(fd, value, ret);
-
-    else
+    for_each_match_area(iter, matches->areas)
     {
-        log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!");
-        write(fd, "null", 4);
-    }
-
-    write(fd, ",\n", 2);
+        /* Marqueur de début */
 
-    /* Affichage du contenu brut */
+        for (i = 0; i < (level + 1); i++)
+            write(fd, padding->data, padding->len);
 
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
+        write(fd, "{\n", 2);
 
-    write(fd, "\"content\": \"", 12);
+        /* Position dans le binaire (décimal) */
 
-    init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL);
+        for (i = 0; i < (level + 2); i++)
+            write(fd, padding->data, padding->len);
 
-    data = g_binary_content_get_raw_access(match->content, &pos, match->len);
-    assert(data != NULL);
+        write(fd, "\"offset\": ", 10);
 
-    for (k = 0; k < match->len; k++)
-    {
-        if (data[k] == '\\')
-            write(fd, "\\\\", 2);
+        ret = snprintf(value, ULLONG_MAXLEN, "%llu", (unsigned long long)iter->start);
 
-        else if (isprint(data[k]))
-            write(fd, &data[k], 1);
+        if (ret > 0)
+            write(fd, value, ret);
 
         else
         {
-            write(fd, "\\u", 2);
+            log_simple_message(LMT_EXT_ERROR, "Error while converting offset!");
+            write(fd, "null", 4);
+        }
 
-            /**
-             * Cf. https://datatracker.ietf.org/doc/html/rfc8259#section-7
-             */
-            ret = snprintf(value, ULLONG_MAXLEN, "%04hhx", data[k]);
+        write(fd, ",\n", 2);
 
-            if (ret > 0)
-            {
-                assert(ret == 4);
-                write(fd, value, ret);
-            }
+        /* Position dans le binaire (hexadécimal) */
 
-            else
-            {
-                log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
-                write(fd, "??", 2);
-            }
+        for (i = 0; i < (level + 2); i++)
+            write(fd, padding->data, padding->len);
 
-        }
+        write(fd, "\"offset_hex\": ", 14);
 
-    }
+        ret = snprintf(value, ULLONG_MAXLEN, "\"0x%llx\"", (unsigned long long)iter->start);
 
-    write(fd, "\",\n", 3);
+        if (ret > 0)
+            write(fd, value, ret);
 
-    /* Affichage du contenu en version humainement lisible */
+        else
+        {
+            log_simple_message(LMT_EXT_ERROR, "Error while converting offset to hex!");
+            write(fd, "null", 4);
+        }
 
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
+        write(fd, ",\n", 2);
 
-    write(fd, "\"content_str\": \"", 16);
+        /* Affichage du contenu brut */
 
-    init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL);
+        for (i = 0; i < (level + 2); i++)
+            write(fd, padding->data, padding->len);
 
-    data = g_binary_content_get_raw_access(match->content, &pos, match->len);
-    assert(data != NULL);
+        write(fd, "\"content\": \"", 12);
 
-    for (k = 0; k < match->len; k++)
-    {
-        if (data[k] == '\\')
-            write(fd, "\\\\", 2);
+        init_vmpa(&pos, iter->start, VMPA_NO_VIRTUAL);
 
-        else if (isprint(data[k]))
-            write(fd, &data[k], 1);
+        len = iter->end - iter->start;
 
-        else
+        data = g_binary_content_get_raw_access(content, &pos, len);
+        assert(data != NULL);
+
+        for (k = 0; k < len; k++)
         {
-            write(fd, "\\\\x", 3);
+            if (data[k] == '\\')
+                write(fd, "\\\\", 2);
 
-            ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]);
+            else if (isprint(data[k]))
+                write(fd, &data[k], 1);
 
-            if (ret > 0)
+            else
             {
-                assert(ret == 2);
-                write(fd, value, ret);
+                write(fd, "\\u", 2);
+
+                /**
+                 * Cf. https://datatracker.ietf.org/doc/html/rfc8259#section-7
+                 */
+                ret = snprintf(value, ULLONG_MAXLEN, "%04hhx", data[k]);
+
+                if (ret > 0)
+                {
+                    assert(ret == 4);
+                    write(fd, value, ret);
+                }
+
+                else
+                {
+                    log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+                    write(fd, "??", 2);
+                }
+
             }
 
+        }
+
+        write(fd, "\",\n", 3);
+
+        /* Affichage du contenu en version humainement lisible */
+
+        for (i = 0; i < (level + 2); i++)
+            write(fd, padding->data, padding->len);
+
+        write(fd, "\"content_str\": \"", 16);
+
+        init_vmpa(&pos, iter->start, VMPA_NO_VIRTUAL);
+
+        data = g_binary_content_get_raw_access(content, &pos, len);
+        assert(data != NULL);
+
+        for (k = 0; k < len; k++)
+        {
+            if (data[k] == '\\')
+                write(fd, "\\\\", 2);
+
+            else if (isprint(data[k]))
+                write(fd, &data[k], 1);
+
             else
             {
-                log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
-                write(fd, "??", 2);
+                write(fd, "\\\\x", 3);
+
+                ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]);
+
+                if (ret > 0)
+                {
+                    assert(ret == 2);
+                    write(fd, value, ret);
+                }
+
+                else
+                {
+                    log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+                    write(fd, "??", 2);
+                }
+
             }
 
         }
 
-    }
+        write(fd, "\",\n", 3);
 
-    write(fd, "\",\n", 3);
+        /* Affichage du contenu brut */
 
-    /* Affichage du contenu brut */
+        for (i = 0; i < (level + 2); i++)
+            write(fd, padding->data, padding->len);
 
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
+        write(fd, "\"length\": ", 10);
 
-    write(fd, "\"length\": ", 10);
+        ret = snprintf(value, ULLONG_MAXLEN, "%llu", (unsigned long long)len);
 
-    init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL);
+        if (ret > 0)
+            write(fd, value, ret);
 
-    ret = snprintf(value, ULLONG_MAXLEN, "%llu", (unsigned long long)match->len);
+        else
+        {
+            log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+            write(fd, "-1", 2);
+        }
 
-    if (ret > 0)
-        write(fd, value, ret);
+        write(fd, ",\n", 2);
 
-    else
-    {
-        log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
-        write(fd, "-1", 2);
-    }
+        /* Affichage du contenu brut (hexadécimal) */
 
-    write(fd, ",\n", 2);
+        for (i = 0; i < (level + 2); i++)
+            write(fd, padding->data, padding->len);
 
-    /* Affichage du contenu brut (hexadécimal) */
+        write(fd, "\"length_hex\": ", 14);
 
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
+        ret = snprintf(value, ULLONG_MAXLEN, "\"0x%llx\"", (unsigned long long)len);
 
-    write(fd, "\"length_hex\": ", 14);
+        if (ret > 0)
+            write(fd, value, ret);
 
-    init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL);
+        else
+        {
+            log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+            write(fd, "\"0xffffffffffffffff\"", 20);
+        }
 
-    ret = snprintf(value, ULLONG_MAXLEN, "\"0x%llx\"", (unsigned long long)match->len);
+        write(fd, "\n", 1);
 
-    if (ret > 0)
-        write(fd, value, ret);
+        /* Marqueur de fin */
+
+        for (i = 0; i < (level + 1); i++)
+            write(fd, padding->data, padding->len);
+
+        if (is_last_match_area(iter, matches->areas))
+            write(fd, "}\n", 2);
+        else
+            write(fd, "},\n", 3);
 
-    else
-    {
-        log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
-        write(fd, "\"0xffffffffffffffff\"", 20);
     }
 
-    write(fd, "\n", 1);
+    g_object_unref(G_OBJECT(content));
+
+    for (i = 0; i < level; i++)
+        write(fd, padding->data, padding->len);
+
+    write(fd, "]\n", 2);
 
 }
diff --git a/src/analysis/scan/matches/bytes.h b/src/analysis/scan/matches/bytes.h
index bd7425d..9e046aa 100644
--- a/src/analysis/scan/matches/bytes.h
+++ b/src/analysis/scan/matches/bytes.h
@@ -1,6 +1,6 @@
 
 /* Chrysalide - Outil d'analyse de fichiers binaires
- * bytes.h - prototypes pour la sauvegarde d'une correspondance identifiée de suite d'octets
+ * bytes.h - prototypes pour la sauvegarde de correspondances avec des suites d'octets identifiées
  *
  * Copyright (C) 2022 Cyrille Bagard
  *
@@ -28,43 +28,53 @@
 #include <glib-object.h>
 
 
-#include "../match.h"
-#include "../../content.h"
+#include "area.h"
+#include "../context.h"
+#include "../matches.h"
 
 
 
-#define G_TYPE_SCAN_BYTES_MATCH            g_scan_bytes_match_get_type()
-#define G_SCAN_BYTES_MATCH(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_BYTES_MATCH, GScanBytesMatch))
-#define G_IS_SCAN_BYTES_MATCH(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_BYTES_MATCH))
-#define G_SCAN_BYTES_MATCH_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_BYTES_MATCH, GScanBytesMatchClass))
-#define G_IS_SCAN_BYTES_MATCH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_BYTES_MATCH))
-#define G_SCAN_BYTES_MATCH_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_BYTES_MATCH, GScanBytesMatchClass))
+/* -------------------- CONSERVATION DE CORRESPONDANCES ETABLIES -------------------- */
 
 
-/* Correspondance trouvée avec une chaîne (instance) */
-typedef struct _GScanBytesMatch GScanBytesMatch;
+#define G_TYPE_SCAN_BYTES_MATCHES            g_scan_bytes_matches_get_type()
+#define G_SCAN_BYTES_MATCHES(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_BYTES_MATCHES, GScanBytesMatches))
+#define G_IS_SCAN_BYTES_MATCHES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_BYTES_MATCHES))
+#define G_SCAN_BYTES_MATCHES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_BYTES_MATCHES, GScanBytesMatchesClass))
+#define G_IS_SCAN_BYTES_MATCHES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_BYTES_MATCHES))
+#define G_SCAN_BYTES_MATCHES_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_BYTES_MATCHES, GScanBytesMatchesClass))
 
-/* Correspondance trouvée avec une chaîne (classe) */
-typedef struct _GScanBytesMatchClass GScanBytesMatchClass;
 
+/* Correspondances trouvées avec des suite d'octets (instance) */
+typedef struct _GScanBytesMatches GScanBytesMatches;
 
-/* Indique le type défini pour un correspondance de chaîne identifiée. */
-GType g_scan_bytes_match_get_type(void);
+/* Correspondances trouvées avec des suite d'octets (classe) */
+typedef struct _GScanBytesMatchesClass GScanBytesMatchesClass;
 
-/* Prend note d'une correspondance trouvée avec un motif. */
-GScanMatch *g_scan_bytes_match_new(GSearchPattern *, GBinContent *, phys_t, phys_t);
 
-/* Fournit une référence au contenu lié à la correspondance. */
-GBinContent *g_scan_bytes_match_get_content(const GScanBytesMatch *);
+/* Indique le type défini pour une série de correspondances d'octets identifiées. */
+GType g_scan_bytes_matches_get_type(void);
 
-/* Indique la localisation d'une correspondance établie. */
-phys_t g_scan_bytes_match_get_location(const GScanBytesMatch *, phys_t *, phys_t *);
+/* Crée un suivi pour série de correspondances avec des octets. */
+GScanMatches *g_scan_bytes_matches_new(GSearchPattern *, GScanContext *);
+
+/* Fournit le contexte du scan associé aux correspondances. */
+GScanContext *g_scan_bytes_matches_get_context(const GScanBytesMatches *);
+
+/* Intègre une liste de correspondances vérifiées. */
+void g_scan_bytes_matches_set_list(GScanBytesMatches *, match_area_t *, size_t);
 
-/* Mémorise l'origine d'une correspondance à partir d'un indice. */
-void g_scan_bytes_match_remember_modifier_path(GScanBytesMatch *, size_t);
+/* Indique le nombre de correspondances pour une définition. */
+size_t g_scan_bytes_matches_count(const GScanBytesMatches *);
+
+/* Fournit les informations relatives à une correspondance. */
+const match_area_t *g_scan_bytes_matches_get(const GScanBytesMatches *, size_t);
+
+/* Indique la localisation d'une correspondance établie. */
+phys_t g_scan_bytes_matches_get_location(const GScanBytesMatches *, size_t, phys_t *, phys_t *);
 
 /* Retrouve l'origine d'une correspondance à partir d'un indice. */
-char *g_scan_bytes_match_get_modifier_path(const GScanBytesMatch *);
+char *g_scan_bytes_matches_get_modifier_path(const GScanBytesMatches *);
 
 
 
diff --git a/src/analysis/scan/matches/pending.c b/src/analysis/scan/matches/pending.c
index 57c63d7..c653257 100644
--- a/src/analysis/scan/matches/pending.c
+++ b/src/analysis/scan/matches/pending.c
@@ -33,6 +33,8 @@
 
 
 
+
+
 /* ------------------------- MEMORISATION D'UNE ZONE BORNEE ------------------------- */
 
 
@@ -48,6 +50,8 @@ static int compare_match_area(const match_area_t *, const match_area_t *);
 
 
 
+
+
 /* ---------------------------------------------------------------------------------- */
 /*                           MEMORISATION D'UNE ZONE BORNEE                           */
 /* ---------------------------------------------------------------------------------- */
@@ -55,6 +59,104 @@ static int compare_match_area(const match_area_t *, const match_area_t *);
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : allocator = allocateur dédié à l'ensemble de zones.          *
+*                start     = point de départ d'une nouvelle correspondance.   *
+*                length    = taille de la zone couverte.                      *
+*                                                                             *
+*  Description : Crée une nouvelle structure de suivi de correspondance.      *
+*                                                                             *
+*  Retour      : Structure initialisée mise en place.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static match_area_t *create_match_area(GUMemCache *allocator, phys_t start, phys_t length)
+{
+    match_area_t *result;                   /* Zone à retourner            */
+
+    result = g_umem_cache_alloc(allocator);
+
+    DL_LIST_ITEM_INIT(&result->link);
+
+    result->start = start;
+    result->end = start + length;
+
+    assert(matches->content_start <= result->start);
+    assert(result->end <= matches->content_end);
+
+    result->ttl = 1;
+
+    result->has_mod_path = false;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : allocator = allocateur dédié à l'ensemble de zones.          *
+*                start     = point de départ d'une nouvelle correspondance.   *
+*                length    = taille de la zone couverte.                      *
+*                index     = indice de construction pour le motif concerné.   *
+*                                                                             *
+*  Description : Crée une nouvelle structure de suivi de correspondance.      *
+*                                                                             *
+*  Retour      : Structure initialisée mise en place.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static match_area_t *create_match_area_with_path(GUMemCache *allocator, phys_t start, phys_t length, size_t index)
+{
+    match_area_t *result;                   /* Zone à retourner            */
+
+    result = g_umem_cache_alloc(allocator);
+
+    DL_LIST_ITEM_INIT(&result->link);
+
+    result->start = start;
+    result->end = start + length;
+
+    assert(matches->content_start <= result->start);
+    assert(result->end <= matches->content_end);
+
+    result->ttl = 1;
+
+    result->mod_path_index = index;
+    result->has_mod_path = true;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : area      = zone de suivi à supprimer.                       *
+*                allocator = allocateur dédié à l'ensemble de zones.          *
+*                                                                             *
+*  Description : Supprime une structure de suivi de correspondance.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void delete_match_area(match_area_t *area, GUMemCache *allocator)
+{
+    // TODO : assert(alone)
+
+    g_umem_cache_free(allocator, area);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : a = pointeur vers la première zone à analyser.               *
 *                b = pointeur vers la seconde zone à analyser.                *
 *                                                                             *
@@ -114,6 +216,7 @@ void init_pending_matches(pending_matches_t *matches, const phys_t *start, const
     matches->content_start = *start;
     matches->content_end = *end;
 
+    matches->allocator = NULL;
     matches->areas = NULL;
     matches->allocated = 0;
     matches->used = 0;
@@ -275,27 +378,12 @@ match_area_t * const *get_all_pending_matches(const pending_matches_t *matches,
 
 void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
 {
-    match_area_t *area;                     /* Zone à initialiser          */
-
-    if (matches->used == matches->allocated)
-    {
-        matches->allocated += PENDING_ALLOC_SIZE;
-
-        matches->areas = realloc(matches->areas, matches->allocated * sizeof(match_area_t));
-
-    }
-
-    area = &matches->areas[matches->used++];
+    match_area_t *area;                     /* Nouvelle zone à intégrer    */
 
-    area->start = start;
-    area->end = start + length;
+    area = create_match_area(matches->allocator, start, length);
 
-    assert(matches->content_start <= area->start);
-    assert(area->end <= matches->content_end);
-
-    area->ttl = 1;
-
-    area->has_mod_path = false;
+    dl_list_add_tail(area, &matches->areas, match_area_t, link);
+    matches->used++;
 
 }
 
@@ -317,28 +405,12 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
 
 void add_pending_match_with_path(pending_matches_t *matches, phys_t start, phys_t length, size_t index)
 {
-    match_area_t *area;                     /* Zone à initialiser          */
-
-    if (matches->used == matches->allocated)
-    {
-        matches->allocated += PENDING_ALLOC_SIZE;
-
-        matches->areas = realloc(matches->areas, matches->allocated * sizeof(match_area_t));
-
-    }
-
-    area = &matches->areas[matches->used++];
-
-    area->start = start;
-    area->end = start + length;
-
-    assert(matches->content_start <= area->start);
-    assert(area->end <= matches->content_end);
+    match_area_t *area;                     /* Nouvelle zone à intégrer    */
 
-    area->ttl = 1;
+    area = create_match_area_with_path(matches->allocator, start, length, index);
 
-    area->mod_path_index = index;
-    area->has_mod_path = true;
+    dl_list_add_tail(area, &matches->areas, match_area_t, link);
+    matches->used++;
 
 }
 
diff --git a/src/analysis/scan/matches/pending.h b/src/analysis/scan/matches/pending.h
index f4ac7a2..e430ca1 100644
--- a/src/analysis/scan/matches/pending.h
+++ b/src/analysis/scan/matches/pending.h
@@ -21,7 +21,7 @@
  */
 
 
-#ifndef _ANALYSIS_SCAN_MATCHES_PENDING_H
+#if 0 //ndef _ANALYSIS_SCAN_MATCHES_PENDING_H
 #define _ANALYSIS_SCAN_MATCHES_PENDING_H
 
 
@@ -30,12 +30,20 @@
 
 
 #include "../../content.h"
+#include "../../../common/dllist.h"
+
+
+
+// TODO : move vers ByteMatch
+typedef int GUMemCache;
 
 
 
 /* Couverture d'une correspondance */
 typedef struct _match_area_t
 {
+    DL_LIST_ITEM(link);                     /* Lien vers les maillons      */
+
     phys_t start;                           /* Point de départ             */
     phys_t end;                             /* Point d'arrivée (exclus)    */
 
@@ -52,6 +60,7 @@ typedef struct _pending_matches_t
     phys_t content_start;                   /* Point de début du contenu   */
     phys_t content_end;                     /* Point de fin du contenu     */
 
+    GUMemCache *allocator;                  /* Allocateur pour zones       */
     match_area_t *areas;                    /* Zones couvertes             */
     size_t allocated;                       /* Nombre d'allocations        */
     size_t used;                            /* Nombre de zones             */
diff --git a/src/analysis/scan/pattern.c b/src/analysis/scan/pattern.c
index fe3babc..dc4418c 100644
--- a/src/analysis/scan/pattern.c
+++ b/src/analysis/scan/pattern.c
@@ -332,7 +332,7 @@ void g_search_pattern_output_to_json(const GSearchPattern *pattern, GScanContext
 
     class = G_SEARCH_PATTERN_GET_CLASS(pattern);
 
-    class->to_json(pattern, context, padding, level + 1, fd);
+    class->to_json(pattern, context, padding, level, fd);
 
     /* Conclusion */
 
diff --git a/src/analysis/scan/patterns/Makefile.am b/src/analysis/scan/patterns/Makefile.am
index c520321..989a562 100644
--- a/src/analysis/scan/patterns/Makefile.am
+++ b/src/analysis/scan/patterns/Makefile.am
@@ -10,6 +10,7 @@ libanalysisscanpatterns_la_SOURCES =		\
 	modarg.h								\
 	modifier-int.h							\
 	modifier.h modifier.c					\
+	patid.h									\
 	token-int.h								\
 	token.h token.c
 
diff --git a/src/analysis/scan/patterns/backend-int.h b/src/analysis/scan/patterns/backend-int.h
index b2587df..90daec9 100644
--- a/src/analysis/scan/patterns/backend-int.h
+++ b/src/analysis/scan/patterns/backend-int.h
@@ -33,11 +33,17 @@
 typedef size_t (* get_backend_atom_max_size_fc) (const GEngineBackend *);
 
 /* Inscrit dans le moteur une chaîne de caractères à rechercher. */
-typedef patid_t (* enroll_plain_into_backend_fc) (GEngineBackend *, GScanContext *, const uint8_t *, size_t);
+typedef patid_t (* enroll_plain_into_backend_fc) (GEngineBackend *, const uint8_t *, size_t, uint32_t [2]);
 
 /* Met en ordre les derniers détails avant un premier scan. */
 typedef void (* warm_up_backend_fc) (GEngineBackend *);
 
+/* Récupère les identifiants finaux pour un motif recherché. */
+typedef patid_t (* build_backend_plain_pattern_id_fc) (const GEngineBackend *, const uint32_t [2]);
+
+/* Détermine le nombre d'identifiants constitués. */
+typedef size_t (* count_backend_plain_pattern_ids_fc) (const GEngineBackend *);
+
 /* Parcours un contenu binaire à la recherche de motifs. */
 typedef void (* run_backend_scan_fc) (const GEngineBackend *, GScanContext *);
 
@@ -57,9 +63,11 @@ struct _GEngineBackendClass
 {
     GObjectClass parent;                    /* A laisser en premier        */
 
-    get_backend_atom_max_size_fc get_max_size;  /* Taille maximale d'atome */
-    enroll_plain_into_backend_fc enroll_plain;  /* Inscription simple      */
+    get_backend_atom_max_size_fc get_max_size; /* Taille maximale d'atome  */
+    enroll_plain_into_backend_fc enroll_plain; /* Inscription simpl e      */
     warm_up_backend_fc warm_up;             /* Préchauffage avant analyse  */
+    build_backend_plain_pattern_id_fc build_id; /* Définition d'identifiant*/
+    count_backend_plain_pattern_ids_fc count_ids; /* Décompte des id.      */
     run_backend_scan_fc run_scan;           /* Lancement d'une analyse     */
     output_backend_stats_fc output;         /* Impression de statistiques  */
 
diff --git a/src/analysis/scan/patterns/backend.c b/src/analysis/scan/patterns/backend.c
index 0ecc7fe..50cc889 100644
--- a/src/analysis/scan/patterns/backend.c
+++ b/src/analysis/scan/patterns/backend.c
@@ -155,9 +155,9 @@ size_t g_engine_backend_get_atom_max_size(const GEngineBackend *backend)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : backend = moteur de recherche à manipuler.                   *
-*                context = contexte de l'analyse à mener.                     *
 *                plain   = chaîne de caractères classique à intégrer.         *
 *                len     = taille de cette chaîne.                            *
+*                tmp_id  = identifiants temporaires vers le motif. [OUT]      *
 *                                                                             *
 *  Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
 *                                                                             *
@@ -167,14 +167,14 @@ size_t g_engine_backend_get_atom_max_size(const GEngineBackend *backend)
 *                                                                             *
 ******************************************************************************/
 
-patid_t g_engine_backend_enroll_plain_pattern(GEngineBackend *backend, GScanContext *context, const uint8_t *plain, size_t len)
+bool g_engine_backend_enroll_plain_pattern(GEngineBackend *backend, const uint8_t *plain, size_t len, uint32_t tmp_id[2])
 {
-    patid_t result;                         /* Identifiant à retourner     */
+    bool result;                            /* Bilan à retourner           */
     GEngineBackendClass *class;             /* Classe à activer            */
 
     class = G_ENGINE_BACKEND_GET_CLASS(backend);
 
-    result = class->enroll_plain(backend, context, plain, len);
+    result = class->enroll_plain(backend, plain, len, tmp_id);
 
     return result;
 
@@ -208,6 +208,59 @@ void g_engine_backend_warm_up(GEngineBackend *backend)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                tmp_id  = identifiants temporaires vers le motif. [OUT]      *
+*                                                                             *
+*  Description : Récupère les identifiants finaux pour un motif recherché.    *
+*                                                                             *
+*  Retour      : Identifiant constitué ou INVALID_PATTERN_ID en cas d'échec.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+patid_t g_engine_backend_build_plain_pattern_id(const GEngineBackend *backend, const uint32_t tmp_id[2])
+{
+    patid_t result;                         /* Identifiant à retourner     */
+    GEngineBackendClass *class;             /* Classe à activer            */
+
+    class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+    result = class->build_id(backend, tmp_id);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                                                                             *
+*  Description : Détermine le nombre d'identifiants constitués.               *
+*                                                                             *
+*  Retour      : Quantité de gestionnaires de suivi à prévoir.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_engine_backend_count_plain_pattern_ids(const GEngineBackend *backend)
+{
+    size_t result;                          /* Quantité à retourner        */
+    GEngineBackendClass *class;             /* Classe à activer            */
+
+    class = G_ENGINE_BACKEND_GET_CLASS(backend);
+
+    result = class->count_ids(backend);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
 *                context = lieu d'enregistrement des résultats.               *
 *                                                                             *
 *  Description : Parcours un contenu binaire à la recherche de motifs.        *
diff --git a/src/analysis/scan/patterns/backend.h b/src/analysis/scan/patterns/backend.h
index 8f6b929..71c97d1 100644
--- a/src/analysis/scan/patterns/backend.h
+++ b/src/analysis/scan/patterns/backend.h
@@ -57,11 +57,17 @@ GType g_engine_backend_get_type(void);
 size_t g_engine_backend_get_atom_max_size(const GEngineBackend *);
 
 /* Inscrit dans le moteur une chaîne de caractères à rechercher. */
-patid_t g_engine_backend_enroll_plain_pattern(GEngineBackend *, GScanContext *, const uint8_t *, size_t);
+bool g_engine_backend_enroll_plain_pattern(GEngineBackend *, const uint8_t *, size_t, uint32_t [2]);
 
 /* Met en ordre les derniers détails avant un premier scan. */
 void g_engine_backend_warm_up(GEngineBackend *);
 
+/* Récupère les identifiants finaux pour un motif recherché. */
+patid_t g_engine_backend_build_plain_pattern_id(const GEngineBackend *, const uint32_t [2]);
+
+/* Détermine le nombre d'identifiants constitués. */
+size_t g_engine_backend_count_plain_pattern_ids(const GEngineBackend *);
+
 /* Parcours un contenu binaire à la recherche de motifs. */
 void g_engine_backend_run_scan(const GEngineBackend *, GScanContext *);
 
diff --git a/src/analysis/scan/patterns/backends/acism-int.h b/src/analysis/scan/patterns/backends/acism-int.h
index a8cfd59..af8080f 100644
--- a/src/analysis/scan/patterns/backends/acism-int.h
+++ b/src/analysis/scan/patterns/backends/acism-int.h
@@ -36,7 +36,7 @@
 
 
 
-#define __USE_BYTE_FREQ
+//#define __USE_BYTE_FREQ
 //#define __SORT_BEFORE_BITMASK
 
 
@@ -50,10 +50,14 @@ typedef struct _acism_source_t
     const uint8_t *atoms;                   /* Motif remarquable           */
     size_t len;                             /* Nombre d'octets considérés  */
 
-    patid_t pid;                            /* Identifiant de suivi        */
+    uint32_t coverage[2];                   /* Départ et quantité de suivis*/
 
 } acism_source_t;
 
+#define SOURCE_COVERAGE_START   0
+#define SOURCE_COVERAGE_COUNT   1
+#define SOURCE_COVERAGE_END     1
+
 /* Etude de la fréquence des octets pour attribution des codes */
 typedef struct _acism_freq_rank_t
 {
@@ -81,8 +85,6 @@ typedef struct _acism_trie_node_t
     bin_t data;                             /* Donnée brute représentée    */
     acism_code_t code;                      /* Identifiant du noeud        */
 
-    patid_t pid;                            /* Identifiant de suivi        */
-
     acism_code_t min_child_code;            /* Plus petit code suivant     */
     acism_code_t max_child_code;            /* Plus grand code suivant     */
     size_t children_count;                  /* Nombre de codes suivants    */
@@ -127,6 +129,7 @@ typedef union _acism_state_t
     struct
     {
         uint8_t match : 1;                  /* Correspondance ici          */
+        uint8_t single_source : 1;          /* Unique source à notifier    */
         uint8_t atom_size;                  /* Indice de saut              */
         uint8_t suffix : 1;                 /* Correspondance ailleurs     */
     };
@@ -169,7 +172,7 @@ struct _GAcismBackend
 
     bitfield_t *bitmap_usage;               /* Localisation des usages     */
     acism_state_t *states;                  /* Tableau de transitions      */
-    patid_t *pids;                          /* Identifiants de motifs      */
+    uint32_t *coverages;                    /* Bornes de suivi de positions*/
 
 };
 
diff --git a/src/analysis/scan/patterns/backends/acism.c b/src/analysis/scan/patterns/backends/acism.c
index bceca09..a36e4b7 100644
--- a/src/analysis/scan/patterns/backends/acism.c
+++ b/src/analysis/scan/patterns/backends/acism.c
@@ -58,10 +58,10 @@ static void g_acism_backend_finalize(GAcismBackend *);
 size_t g_acism_backend_get_atom_max_size(const GAcismBackend *);
 
 /* Intègre un motif limité de contenu à rechercher. */
-static patid_t g_acism_backend_setup_for(GAcismBackend *, GScanContext *, const uint8_t *, size_t);
+static void g_acism_backend_setup_for(GAcismBackend *, const uint8_t *, size_t, uint32_t [2]);
 
 /* Inscrit dans le moteur une chaîne de caractères à rechercher. */
-static patid_t g_acism_backend_enroll_plain_pattern(GAcismBackend *, GScanContext *, const uint8_t *, size_t);
+static bool g_acism_backend_enroll_plain_pattern(GAcismBackend *, const uint8_t *, size_t, uint32_t [2]);
 
 #ifdef __USE_BYTE_FREQ
 
@@ -92,9 +92,15 @@ static void g_acism_backend_prepare_interleave_array(GAcismBackend *);
 /* Compresse l'arborescence dans un tableau de position. */
 static void g_acism_backend_build_interleave_array(GAcismBackend *);
 
+/* Détermine le nombre d'identifiants constitués. */
+static size_t g_acism_backend_count_plain_pattern_ids(const GAcismBackend *);
+
 /* Met en ordre les derniers détails avant un premier scan. */
 static void g_acism_backend_warm_up(GAcismBackend *);
 
+/* Récupère les identifiants finaux pour un motif recherché. */
+static patid_t g_acism_backend_build_plain_pattern_id(const GAcismBackend *, const uint32_t [2]);
+
 /* Parcours un contenu binaire à la recherche de motifs. */
 static void g_acism_backend_run_scan(const GAcismBackend *, GScanContext *);
 
@@ -142,6 +148,8 @@ static void g_acism_backend_class_init(GAcismBackendClass *klass)
     backend->get_max_size = (get_backend_atom_max_size_fc)g_acism_backend_get_atom_max_size;
     backend->enroll_plain = (enroll_plain_into_backend_fc)g_acism_backend_enroll_plain_pattern;
     backend->warm_up = (warm_up_backend_fc)g_acism_backend_warm_up;
+    backend->build_id = (build_backend_plain_pattern_id_fc)g_acism_backend_build_plain_pattern_id;
+    backend->count_ids = (count_backend_plain_pattern_ids_fc)g_acism_backend_count_plain_pattern_ids;
     backend->run_scan = (run_backend_scan_fc)g_acism_backend_run_scan;
     backend->output = (output_backend_stats_fc)g_acism_backend_output_stats;
 
@@ -229,8 +237,8 @@ static void g_acism_backend_finalize(GAcismBackend *backend)
     if (backend->states != NULL)
         free(backend->states);
 
-    if (backend->pids != NULL)
-        free(backend->pids);
+    if (backend->coverages != NULL)
+        free(backend->coverages);
 
     G_OBJECT_CLASS(g_acism_backend_parent_class)->finalize(G_OBJECT(backend));
 
@@ -292,9 +300,9 @@ size_t g_acism_backend_get_atom_max_size(const GAcismBackend *backend)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : backend = moteur de recherche à préparer.                    *
-*                context = contexte de l'analyse à mener.                     *
-*                plain   = chaîne de caractères classique à intégrer.         *
+*                pattern = chaîne de caractères classique à intégrer.         *
 *                len     = taille de cette chaîne.                            *
+*                tmp_id  = identifiants temporaires vers le motif. [OUT]      *
 *                                                                             *
 *  Description : Intègre un motif limité de contenu à rechercher.             *
 *                                                                             *
@@ -304,15 +312,12 @@ size_t g_acism_backend_get_atom_max_size(const GAcismBackend *backend)
 *                                                                             *
 ******************************************************************************/
 
-static patid_t g_acism_backend_setup_for(GAcismBackend *backend, GScanContext *context, const uint8_t *pattern, size_t len)
+static void g_acism_backend_setup_for(GAcismBackend *backend, const uint8_t *pattern, size_t len, uint32_t tmp_id[2])
 {
-    patid_t result;                         /* Identifiant à retourner     */
     size_t i;                               /* Boucle de parcours          */
     int ret;                                /* Bilan d'une comparaison     */
     acism_source_t *source;                 /* Définition à mémoriser      */
 
-    result = INVALID_PATTERN_ID;
-
     /*Recherche d'un motif déjà sollicité */
 
     /**
@@ -332,15 +337,19 @@ static patid_t g_acism_backend_setup_for(GAcismBackend *backend, GScanContext *c
 
         if (ret == 0)
         {
-            result = source->pid;
+            tmp_id[0] = i;
+            tmp_id[1] = source->coverage[SOURCE_COVERAGE_COUNT];
+
+            source->coverage[SOURCE_COVERAGE_COUNT]++;
             break;
+
         }
 
     }
 
     /* Introduction d'un nouveau motif au besoin */
 
-    if (result == INVALID_PATTERN_ID)
+    if (i == backend->sources_count)
     {
         backend->sources = realloc(backend->sources, ++backend->sources_count * sizeof(acism_source_t));
 
@@ -349,8 +358,10 @@ static patid_t g_acism_backend_setup_for(GAcismBackend *backend, GScanContext *c
         source->atoms = pattern;
         source->len = len;
 
-        result = g_scan_context_get_new_pattern_id(context);
-        source->pid = result;
+        source->coverage[SOURCE_COVERAGE_COUNT] = 1;
+
+        tmp_id[0] = i;
+        tmp_id[1] = 0;
 
         backend->nchars += len;
 
@@ -361,17 +372,15 @@ static patid_t g_acism_backend_setup_for(GAcismBackend *backend, GScanContext *c
 
     }
 
-    return result;
-
 }
 
 
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : backend = moteur de recherche à manipuler.                   *
-*                context = contexte de l'analyse à mener.                     *
 *                plain   = chaîne de caractères classique à intégrer.         *
 *                len     = taille de cette chaîne.                            *
+*                tmp_id  = identifiants temporaires vers le motif. [OUT]      *
 *                                                                             *
 *  Description : Inscrit dans le moteur une chaîne de caractères à rechercher.*
 *                                                                             *
@@ -381,12 +390,14 @@ static patid_t g_acism_backend_setup_for(GAcismBackend *backend, GScanContext *c
 *                                                                             *
 ******************************************************************************/
 
-static patid_t g_acism_backend_enroll_plain_pattern(GAcismBackend *backend, GScanContext *context, const uint8_t *plain, size_t len)
+static bool g_acism_backend_enroll_plain_pattern(GAcismBackend *backend, const uint8_t *plain, size_t len, uint32_t tmp_id[2])
 {
-    patid_t result;                         /* Identifiant à retourner     */
+    bool result;                            /* Bilan à retourner           */
 
     assert(len <= ACSIM_ATOM_SIZE);
 
+    result = true;
+
     /**
      * Le traitement différé des chaînes à rechercher permet deux choses :
      *   - la construction d'une table de permutation ;
@@ -405,7 +416,7 @@ static patid_t g_acism_backend_enroll_plain_pattern(GAcismBackend *backend, GSca
      * moindre coût un jour.
      */
 
-    result = g_acism_backend_setup_for(backend, context, plain, len);
+    g_acism_backend_setup_for(backend, plain, len, tmp_id);
 
     return result;
 
@@ -505,6 +516,7 @@ static void g_acism_backend_define_codes(GAcismBackend *backend)
 static void g_acism_backend_build_trie(GAcismBackend *backend)
 {
     size_t i;                               /* Boucle de parcours #1       */
+    uint32_t current_start;                 /* Indice de gestionnaire      */
     acism_trie_node_t *next;                /* Prochain noeud disponible   */
     acism_trie_node_t *node;                /* Tête de parcours            */
     acism_source_t *source;                 /* Définition à mémoriser      */
@@ -520,6 +532,8 @@ static void g_acism_backend_build_trie(GAcismBackend *backend)
         backend->nodes[i].max_child_code = MIN_ACISM_CODE;
     }
 
+    current_start = 0;
+
     next = backend->nodes + 1;
 
     for (i = 0; i < backend->sources_count; i++)
@@ -528,6 +542,15 @@ static void g_acism_backend_build_trie(GAcismBackend *backend)
 
         source = &backend->sources[i];
 
+        /* Mise à jour de la couverture des gestionnaires de suivi */
+
+        source->coverage[SOURCE_COVERAGE_START] = current_start;
+        source->coverage[SOURCE_COVERAGE_END] += current_start;
+
+        current_start = source->coverage[SOURCE_COVERAGE_END];
+
+        /* Parcours des noeuds contenus */
+
         for (k = 0; k < source->len && node->child != NULL; k++)
         {
 #ifdef __USE_BYTE_FREQ
@@ -1026,6 +1049,8 @@ static void g_acism_backend_build_interleave_array(GAcismBackend *backend)
     size_t i;                               /* Boucle de parcours #1       */
     acism_trie_node_t *node;                /* Noeud à transcrire          */
     acism_state_t *base;                    /* Base d'une série de cellules*/
+    uint32_t *coverage;                     /* Couverture des inscriptions */
+    acism_source_t *source;                 /* Définition originelle       */
     acism_trie_node_t *iter;                /* Sous-noeud à inscrire #2    */
     acism_trie_node_t *child;               /* Sous-noeud à inscrire #3    */
     uint16_t offset;                        /* Décalage local              */
@@ -1033,7 +1058,7 @@ static void g_acism_backend_build_interleave_array(GAcismBackend *backend)
     maxsize = get_bit_field_size(backend->bitmap_usage);
 
     backend->states = calloc(maxsize, sizeof(acism_state_t));
-    backend->pids = calloc(maxsize, sizeof(patid_t));
+    backend->coverages = calloc(maxsize, 2 * sizeof(uint32_t));
 
     for (i = 0; i < backend->nodes_used; i++)
     {
@@ -1045,10 +1070,15 @@ static void g_acism_backend_build_interleave_array(GAcismBackend *backend)
 
         if (node->matched_atom > 0)
         {
+            source = &backend->sources[node->matched_atom - 1];
+
             base[0].match = 1;
+            base[0].single_source = source->coverage[SOURCE_COVERAGE_COUNT] == 1 ? 1 : 0;
             base[0].atom_size = backend->sources[node->matched_atom - 1].len - 1;
+            coverage = &backend->coverages[node->state_index * 2];
 
-            backend->pids[node->state_index] = backend->sources[node->matched_atom - 1].pid;
+            coverage[SOURCE_COVERAGE_START] = source->coverage[SOURCE_COVERAGE_START];
+            coverage[SOURCE_COVERAGE_COUNT] = source->coverage[SOURCE_COVERAGE_COUNT];
 
             for (iter = node->parent->suffix_link; iter != NULL; iter = iter->suffix_link)
             {
@@ -1065,6 +1095,7 @@ static void g_acism_backend_build_interleave_array(GAcismBackend *backend)
             }
 
         }
+
         base[0].index = i == 0 ? 0 : node->suffix_link->state_index;
 
         for (child = node->child; child != NULL; child = child->sibling)
@@ -1111,6 +1142,10 @@ static void g_acism_backend_warm_up(GAcismBackend *backend)
     /**
      * Construit une arborescence de lecture à partir des différents
      * octets présents dans les motifs.
+     *
+     * Les couvertures des futurs tableaux de correspondances sont
+     * établies au passage, ouvrant la voie aux définitions d'identifiant
+     * pour les motifs enregistrés.
      */
     g_acism_backend_build_trie(backend);
 
@@ -1134,6 +1169,58 @@ static void g_acism_backend_warm_up(GAcismBackend *backend)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                tmp_id  = identifiants temporaires vers le motif. [OUT]      *
+*                                                                             *
+*  Description : Récupère les identifiants finaux pour un motif recherché.    *
+*                                                                             *
+*  Retour      : Identifiant constitué ou INVALID_PATTERN_ID en cas d'échec.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static patid_t g_acism_backend_build_plain_pattern_id(const GAcismBackend *backend, const uint32_t tmp_id[2])
+{
+    patid_t result;                         /* Identifiant à retourner     */
+    acism_source_t *source;                 /* Motif d'origine concerné    */
+
+    source = backend->sources + tmp_id[0];
+
+    result = source->coverage[SOURCE_COVERAGE_START] + tmp_id[1];
+
+    assert(result < source->coverage[SOURCE_COVERAGE_END]);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
+*                                                                             *
+*  Description : Détermine le nombre d'identifiants constitués.               *
+*                                                                             *
+*  Retour      : Quantité de gestionnaires de suivi à prévoir.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static size_t g_acism_backend_count_plain_pattern_ids(const GAcismBackend *backend)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    result = backend->sources[backend->sources_count -1].coverage[SOURCE_COVERAGE_END];
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : backend = moteur de recherche à manipuler.                   *
 *                context = lieu d'enregistrement des résultats.               *
 *                                                                             *
 *  Description : Parcours un contenu binaire à la recherche de motifs.        *
@@ -1150,17 +1237,20 @@ static void g_acism_backend_run_scan(const GAcismBackend *backend, GScanContext
     phys_t dlen;                            /* Quantité de données         */
     vmpa2t pos;                             /* Point de départ ciblé       */
     const bin_t *data;                      /* Données à analyser          */
+    GUMemSlice **matches;                   /* Zones d'enregistrements     */
 #ifdef __USE_BYTE_FREQ
     acism_code_t codes_for_bytes[256];      /* Copie des codes d'accès     */
 #endif
     acism_state_t *root;                    /* Racine de l'arborescence    */
-    patid_t *pids;                          /* Identifiants de motifs      */
+    uint32_t *coverages;                    /* Bornes de suivi de positions*/
     unsigned int state;                     /* Tête de lecture courante    */
     phys_t i;                               /* Boucle de parcours #1       */
     acism_code_t code;                      /* Code du caractère courant   */
     unsigned int next;                      /* Prochaine tête à valider    */
     acism_state_t next_state;               /* Prochaine tête à valider    */
-    unsigned int iter;                      /* Boucle de parcours #2       */
+    uint32_t final_k;                       /* Dernier indice à traiter    */
+    uint32_t k;                             /* Boucle de parcours #2       */
+    unsigned int iter;                      /* Boucle de parcours #3       */
     acism_state_t test_state;               /* Test de validité alternative*/
     acism_state_t sub_state;                /* Test de validité alternative*/
 
@@ -1171,6 +1261,8 @@ static void g_acism_backend_run_scan(const GAcismBackend *backend, GScanContext
     g_binary_content_compute_start_pos(content, &pos);
     data = g_binary_content_get_raw_access(content, &pos, dlen);
 
+    matches = g_scan_context_get_match_storages(context, (size_t []){ 0 });
+
     /* Suivi via l'arborescence aplatie */
 
 #ifdef __USE_BYTE_FREQ
@@ -1180,7 +1272,7 @@ static void g_acism_backend_run_scan(const GAcismBackend *backend, GScanContext
     root = backend->states;
     if (root == NULL) goto done;
 
-    pids = backend->pids;
+    coverages = backend->coverages;
 
     state = ROOT_STATE_INDEX;
 
@@ -1217,9 +1309,19 @@ static void g_acism_backend_run_scan(const GAcismBackend *backend, GScanContext
 
         if (next_state.match)
         {
-            g_scan_context_register_atom_match(context,
-                                               pids[next],
-                                               i - next_state.atom_size);
+            k = coverages[next * 2 + SOURCE_COVERAGE_START];
+
+            if (next_state.single_source)
+                g_umem_slice_put_uint64(matches[k], i - next_state.atom_size);
+
+            else
+            {
+                final_k = coverages[next * 2 + SOURCE_COVERAGE_END];
+
+                for (; k < final_k; k++)
+                    g_umem_slice_put_uint64(matches[k], i - next_state.atom_size);
+
+            }
 
             if (next_state.suffix)
             {
@@ -1235,9 +1337,19 @@ static void g_acism_backend_run_scan(const GAcismBackend *backend, GScanContext
                         {
                             assert(sub_state.atom_size < next_state.atom_size);
 
-                            g_scan_context_register_atom_match(context,
-                                                               pids[test_state.index],
-                                                               i - sub_state.atom_size);
+                            k = coverages[test_state.index * 2 + SOURCE_COVERAGE_START];
+
+                            if (sub_state.single_source)
+                                g_umem_slice_put_uint64(matches[k], i - sub_state.atom_size);
+
+                            else
+                            {
+                                final_k = coverages[test_state.index * 2 + SOURCE_COVERAGE_END];
+
+                                for (; k < final_k; k++)
+                                    g_umem_slice_put_uint64(matches[k], i - sub_state.atom_size);
+
+                            }
 
                         }
 
diff --git a/src/analysis/scan/patterns/backends/bitap.c b/src/analysis/scan/patterns/backends/bitap.c
index 99e16e5..af50c6d 100644
--- a/src/analysis/scan/patterns/backends/bitap.c
+++ b/src/analysis/scan/patterns/backends/bitap.c
@@ -517,7 +517,7 @@ static patid_t enroll_plain_pattern_avx2(GBitapBackend *backend, GScanContext *c
 
     last->m[n] = plen;
 
-    result = g_scan_context_get_new_pattern_id(context);
+    result = 0; // FIXME g_scan_context_get_new_pattern_id(context);
 
     last->found_id[n] = result;
 
@@ -934,9 +934,11 @@ static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, c
                     {
                         //assert((i + 1) >= group.m[j]);
 
+                        /** TODO : update call
                         g_scan_context_register_atom_match(context,
                                                            group.found_id[j],
                                                            (iter - data) + 1 - group.m[j]);
+                        **/
 
                     }
 
@@ -1108,9 +1110,11 @@ static void run_scan_avx2(const GBitapBackend *backend, GScanContext *context, c
                     {
                         //assert((i + 1) >= group.m[j]);
 
+                        /** TODO : update call
                         g_scan_context_register_atom_match(context,
                                                            group.found_id[j],
                                                            (iter - data) + 1 - group.m[j]);
+                        **/
 
                     }
 
@@ -1617,7 +1621,7 @@ static patid_t enroll_plain_pattern_avx512(GBitapBackend *backend, GScanContext
 
     last->m[n] = plen;
 
-    result = g_scan_context_get_new_pattern_id(context);
+    result = 0; // FIXME g_scan_context_get_new_pattern_id(context);
 
     last->found_id[n] = result;
 
@@ -1925,9 +1929,11 @@ static void run_scan_avx512(const GBitapBackend *backend, GScanContext *context,
                     {
                         //assert((i + 1) >= group.m[j]);
 
+                        /** TODO : update call
                         g_scan_context_register_atom_match(context,
                                                            group.found_id[j],
                                                            (iter - data) + 1 - group.m[j]);
+                        **/
 
                     }
 
@@ -1946,9 +1952,11 @@ static void run_scan_avx512(const GBitapBackend *backend, GScanContext *context,
                     {
                         //assert((i + 1) >= group.m[j]);
 
+                        /** TODO : update call
                         g_scan_context_register_atom_match(context,
                                                            _group->found_id[j],
                                                            (iter - data) + 1 - _group->m[j]);
+                        **/
 
                     }
 
diff --git a/src/analysis/scan/patterns/patid.h b/src/analysis/scan/patterns/patid.h
new file mode 100644
index 0000000..e8b7eee
--- /dev/null
+++ b/src/analysis/scan/patterns/patid.h
@@ -0,0 +1,36 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * patid.h - prototypes pour la définition d'un identifiant de motif partiel
+ *
+ * Copyright (C) 2023 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 <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _ANALYSIS_SCAN_PATTERNS_PATID_H
+#define _ANALYSIS_SCAN_PATTERNS_PATID_H
+
+
+
+/* Identifiant de motif intégré */
+typedef uint32_t patid_t;
+
+#define INVALID_PATTERN_ID 0xffffffff
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_PATID_H */
diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c
index e5eb287..76a5e66 100644
--- a/src/analysis/scan/patterns/token.c
+++ b/src/analysis/scan/patterns/token.c
@@ -248,7 +248,6 @@ bool g_bytes_token_is_private(const GBytesToken *token)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : token   = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                maxsize = taille max. des atomes (mise en commun optimisée). *
 *                                                                             *
@@ -260,13 +259,37 @@ bool g_bytes_token_is_private(const GBytesToken *token)
 *                                                                             *
 ******************************************************************************/
 
-bool g_bytes_token_enroll(GBytesToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+bool g_bytes_token_enroll(GBytesToken *token, GEngineBackend *backend, size_t maxsize)
 {
     bool result;                            /* Statut à retourner          */
 
     token->need_backward = g_scan_token_node_setup_tree(token->root);
 
-    result = g_scan_token_node_enroll(token->root, context, backend, maxsize, &token->slow);
+    result = g_scan_token_node_enroll(token->root, backend, maxsize, &token->slow);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : token   = définition de la bribe à peaufiner.                *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère les identifiants finaux pour un motif recherché.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_bytes_token_build_id(GBytesToken *token, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+
+    result = g_scan_token_node_build_id(token->root, backend);
 
     return result;
 
@@ -276,8 +299,6 @@ bool g_bytes_token_enroll(GBytesToken *token, GScanContext *context, GEngineBack
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : token   = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
 *                matches = suivi des correspondances à consolider.            *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
@@ -288,60 +309,98 @@ bool g_bytes_token_enroll(GBytesToken *token, GScanContext *context, GEngineBack
 *                                                                             *
 ******************************************************************************/
 
-void g_bytes_token_check(const GBytesToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+void g_bytes_token_check(const GBytesToken *token, GScanBytesMatches *matches)
 {
-    size_t p;                               /* Boucle de parcours #3       */
-    match_area_t *pending;                  /* Correspondance à traiter    */
+    scan_node_check_params_t params;        /* Rassemblement de paramètres */
+    vmpa2t start;                           /* Point de début du contenu   */
+    vmpa2t end;                             /* Point de fin du contenu     */
+    match_area_t *area;                     /* Correspondance à valider    */
+    match_area_t *next;                     /* Correspondance suivante     */
     vmpa2t pos;                             /* Tête de lecture             */
     const bin_t *byte;                      /* Octet à valider             */
 
-    g_scan_token_node_check_forward(token->root, context, content, matches);
+    /* Définition d'un contexte */
+
+    params.context = g_scan_bytes_matches_get_context(matches);
+    params.content = g_scan_context_get_content(params.context);
+    params.allocator = g_umem_slice_new(sizeof(match_area_t));
+
+    g_binary_content_compute_start_pos(params.content, &start);
+    g_binary_content_compute_end_pos(params.content, &end);
+
+    params.content_start = start.physical;
+    params.content_end = end.physical;
+
+    // offset
+
+    params.initialized = false;
+
+    params.main_areas = NULL;
+    params.main_count = 0;
+
+    params.created_areas = NULL;
+    params.created_count = 0;
+
+    params.kept_areas = NULL;
+    params.kept_count = 0;
+
+    /* Lancement des analyses */
+
+    g_scan_token_node_check_forward(token->root, &params);
 
     if (token->need_backward)
-        g_scan_token_node_check_backward(token->root, context, content, matches);
+        g_scan_token_node_check_backward(token->root, &params);
 
-    sort_and_filter_pending_matches(matches);
+    // REMME ? sort_and_filter_pending_matches(matches);
 
     if (token->fullword)
     {
-        reset_pending_matches_ttl(matches);
-
-        for (p = 0; p < matches->used; p++)
+        for_each_match_area_safe(area, &params.main_areas, next)
         {
-            pending = &matches->areas[p];
-
             /* Validation de l'octet précédent, s'il existe */
-            if (pending->start > matches->content_start)
+            if (area->start > params.content_start)
             {
-                init_vmpa(&pos, pending->start - 1, VMPA_NO_VIRTUAL);
+                init_vmpa(&pos, area->start - 1, VMPA_NO_VIRTUAL);
 
-                byte = g_binary_content_get_raw_access(content, &pos, 1);
+                byte = g_binary_content_get_raw_access(params.content, &pos, 1);
 
                 if (isalnum(*byte))
+                {
+                    del_match_area(area, &params.main_areas);
+                    assert(&params.main_count > 0);
+                    params.main_count--;
                     continue;
+                }
 
             }
 
             /* Validation de l'octet suivant, s'il existe */
-            if (pending->end < matches->content_end)
+            if (area->end < params.content_end)
             {
-                init_vmpa(&pos, pending->end, VMPA_NO_VIRTUAL);
+                init_vmpa(&pos, area->end, VMPA_NO_VIRTUAL);
 
-                byte = g_binary_content_get_raw_access(content, &pos, 1);
+                byte = g_binary_content_get_raw_access(params.content, &pos, 1);
 
                 if (isalnum(*byte))
+                {
+                    del_match_area(area, &params.main_areas);
+                    assert(&params.main_count > 0);
+                    params.main_count--;
                     continue;
+                }
 
             }
 
-            keep_pending_match(pending);
-
         }
 
-        purge_pending_matches(matches);
-
     }
 
+    g_scan_bytes_matches_set_list(matches, params.main_areas, params.main_count);
+
+    g_object_unref(G_OBJECT(params.context));
+    g_object_unref(G_OBJECT(params.content));
+    //g_object_unref(G_OBJECT(params.allocator));
+
 }
 
 
@@ -394,17 +453,20 @@ char *g_bytes_token_get_modifier_path(const GBytesToken *token, size_t index)
 
 static void g_bytes_token_output_to_text(const GBytesToken *pattern, GScanContext *context, int fd)
 {
-    const GScanMatch **matches;             /* Correspondances établies    */
-    size_t count;                           /* Quantité de cette liste     */
-    size_t i;                               /* Boucle de parcours          */
+    GScanMatches *matches;                  /* Correspondances établies    */
 
     if (g_bytes_token_is_private(pattern))
         return;
 
-    matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
+    matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern));
 
-    for (i = 0; i < count; i++)
-        g_scan_match_output_to_text(matches[i], fd);
+    if (matches != NULL)
+    {
+        g_scan_matches_output_to_text(matches, fd);
+    
+        g_object_unref(G_OBJECT(matches));
+
+    }
 
 }
 
@@ -427,57 +489,19 @@ static void g_bytes_token_output_to_text(const GBytesToken *pattern, GScanContex
 
 static void g_bytes_token_output_to_json(const GBytesToken *pattern, GScanContext *context, const sized_string_t *padding, unsigned int level, int fd)
 {
-    unsigned int i;                         /* Boucle de parcours #1       */
-    const GScanMatch **matches;             /* Correspondances établies    */
-    size_t count;                           /* Quantité de cette liste     */
-    char value[ULLONG_MAXLEN];              /* Impression de la position   */
-    int ret;                                /* Bilan d'une conversion      */
-    size_t k;                               /* Boucle de parcours #2       */
-    bool trailing;                          /* Virgule finale              */
+    GScanMatches *matches;                  /* Correspondances établies    */
 
     if (g_bytes_token_is_private(pattern))
         return;
 
-    matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
-
-    /* Nombre de correspondances */
-
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
+    matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern));
 
-    write(fd, "\"match_count\": ", 15);
-
-    ret = snprintf(value, ULLONG_MAXLEN, "%zu", count);
-
-    if (ret > 0)
-        write(fd, value, ret);
-
-    else
-    {
-        log_simple_message(LMT_EXT_ERROR, "Error while converting value!");
-        write(fd, "null", 4);
-    }
-
-    write(fd, ",\n", 2);
-
-    /* Détail des correspondances */
-
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
-
-    write(fd, "\"matches\": [\n", 13);
-
-    for (k = 0; k < count; k++)
+    if (matches != NULL)
     {
-        trailing = ((k + 1) < count);
-
-        g_scan_match_output_to_json(matches[k], padding, level + 1, fd, trailing);
+        g_scan_matches_output_to_json(matches, padding, level, fd);
+    
+        g_object_unref(G_OBJECT(matches));
 
     }
 
-    for (i = 0; i < level; i++)
-        write(fd, padding->data, padding->len);
-
-    write(fd, "]\n", 2);
-
 }
diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h
index 2816bf8..3bc5cb7 100644
--- a/src/analysis/scan/patterns/token.h
+++ b/src/analysis/scan/patterns/token.h
@@ -30,7 +30,7 @@
 
 #include "backend.h"
 #include "tokens/node.h"
-#include "../matches/pending.h"
+#include "../matches/bytes.h"
 
 
 
@@ -59,10 +59,13 @@ bool g_bytes_token_target_fullword(const GBytesToken *);
 bool g_bytes_token_is_private(const GBytesToken *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-bool g_bytes_token_enroll(GBytesToken *, GScanContext *, GEngineBackend *, size_t);
+bool g_bytes_token_enroll(GBytesToken *, GEngineBackend *, size_t);
+
+/* Récupère les identifiants finaux pour un motif recherché. */
+bool g_bytes_token_build_id(GBytesToken *, GEngineBackend *);
 
 /* Transforme les correspondances locales en trouvailles. */
-void g_bytes_token_check(const GBytesToken *, GScanContext *, GBinContent *, pending_matches_t *);
+void g_bytes_token_check(const GBytesToken *, GScanBytesMatches *);
 
 /* Retrouve l'origine d'une correspondance à partir d'un indice. */
 char *g_bytes_token_get_modifier_path(const GBytesToken *, size_t);
diff --git a/src/analysis/scan/patterns/tokens/atom.c b/src/analysis/scan/patterns/tokens/atom.c
index 01da28d..580ad30 100644
--- a/src/analysis/scan/patterns/tokens/atom.c
+++ b/src/analysis/scan/patterns/tokens/atom.c
@@ -26,6 +26,7 @@
 
 #include <assert.h>
 #include <malloc.h>
+#include <math.h>
 
 
 
@@ -168,6 +169,8 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
         atom->len = raw->len;
         atom->rem = 0;
 
+        atom->fast_check = true;
+
         if (letters != NULL)
         {
             *letters = 0;
@@ -240,11 +243,16 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
 
         atom->rem = raw->len - atom->pos - maxsize;
 
+        atom->fast_check = false;
+
         if (letters != NULL)
             *letters = best_letters;
 
     }
 
+    assert((atom->fast_check && atom->pos == 0 && atom->rem == 0)
+           || (!atom->fast_check && (atom->pos != 0 || atom->rem != 0)));
+
 }
 
 
@@ -340,11 +348,11 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, const tra
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : byte     = octet partiel à interpréter.                      *
-*                mask     = valeur du masque à appliquer.                     *
+*  Paramètres  : bytes    = octets partiels avec leur masque à interpréter.   *
+*                len      = quantité d'octets à interpréter.                  *
 *                produced = nombre de contenus générés. [OUT]                 *
 *                                                                             *
-*  Description : Etablit la liste des cas de figures avec un octet partiel.   *
+*  Description : Etablit la liste des cas de figures avec des octets partiels.*
 *                                                                             *
 *  Retour      : Liste de toutes les combinaisons possibles.                  *
 *                                                                             *
@@ -352,28 +360,66 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, const tra
 *                                                                             *
 ******************************************************************************/
 
-sized_binary_t *make_atoms_from_masked_byte(bin_t value, bin_t mask, size_t *produced)
+sized_binary_t *make_atoms_from_masked_bytes(const masked_byte_t *bytes, size_t len, size_t *produced)
 {
     sized_binary_t *result;                 /* Liste à retourner           */
+    size_t seq_len;                         /* Taille de séquence retenue  */
+    size_t repeat_times;                    /* Répétitions pour remplissage*/
+    sized_binary_t *maxiter;                /* Borne de fin de parcours    */
     size_t i;                               /* Boucle de parcours #1       */
+    sized_binary_t *iter;                   /* Boucle de parcours #2       */
+    size_t j;                               /* Boucle de parcours #3       */
+    size_t k;                               /* Boucle de parcours #4       */
+
+    seq_len = (len > MASK_MAX_LEN_FOR_ATOMS ? MASK_MAX_LEN_FOR_ATOMS : len);
+
+    /**
+     * Si l'usage de la fonction pow() disparaît, la bibliothèque m
+     * peut être retirée de libchrysacore_la_LDFLAGS dans le Makefile
+     * principal.
+     */
+    repeat_times = pow(16, seq_len - 1);
 
-    *produced = 16;
+    *produced = 16 * repeat_times;
 
     /* Création du réceptacle */
 
-    result = malloc(16 * sizeof(tracked_scan_atom_t));
+    result = malloc(*produced * sizeof(tracked_scan_atom_t));
+
+    maxiter = result + *produced;
 
     /* Remplissage */
 
-    for (i = 0; i < 16; i++)
+    for (i = 0; i < seq_len; i++)
     {
-        result[i].data = malloc(1);
-        result[i].len = 1;
+        for (iter = result; iter < maxiter; )
+        {
+            for (j = 0; j < 16; j++)
+            {
+                assert(bytes[i].mask == 0x0f || bytes[i].mask == 0xf0);
 
-        if (mask == 0x0f)
-            result[i].data[0] = value | (i << 4);
-        else
-            result[i].data[0] = value | i;
+                for (k = 0; k < repeat_times; k++)
+                {
+                    if (i == 0)
+                    {
+                        iter->data = malloc(seq_len);
+                        iter->len = seq_len;
+                    }
+
+                    if (bytes[i].mask == 0x0f)
+                        iter->data[i] = bytes[i].value | (j << 4);
+                    else
+                        iter->data[i] = bytes[i].value | j;
+
+                    iter++;
+
+                }
+
+            }
+
+        }
+
+        repeat_times /= 16;
 
     }
 
@@ -385,11 +431,10 @@ sized_binary_t *make_atoms_from_masked_byte(bin_t value, bin_t mask, size_t *pro
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : raw     = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                atom    = informations de suivi constituées. [OUT]           *
 *                                                                             *
-*  Description : Enregistre l'atome déterminé d'une série d'octets.           *
+*  Description : Amorce l'insertion de l'atome déterminé d'une série d'octets.*
 *                                                                             *
 *  Retour      : Bilan de l'opération à renvoyer.                             *
 *                                                                             *
@@ -397,14 +442,38 @@ sized_binary_t *make_atoms_from_masked_byte(bin_t value, bin_t mask, size_t *pro
 *                                                                             *
 ******************************************************************************/
 
-bool enroll_prepared_atom(const sized_binary_t *raw, GScanContext *context, GEngineBackend *backend, tracked_scan_atom_t *atom)
+bool enroll_prepared_atom(const sized_binary_t *raw, GEngineBackend *backend, tracked_scan_atom_t *atom)
 {
     bool result;                            /* Statut à retourner          */
     const bin_t *data;                      /* Données à rechercher        */
 
     data = raw->data + atom->pos;
 
-    atom->pid = g_engine_backend_enroll_plain_pattern(backend, context, data, atom->len);
+    result = g_engine_backend_enroll_plain_pattern(backend, data, atom->len, atom->tmp_id);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : atom    = informations de suivi constituées. [OUT]           *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère un identifiant final pour un atome d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool build_atom_pattern_id(tracked_scan_atom_t *atom, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+
+    atom->pid = g_engine_backend_build_plain_pattern_id(backend, atom->tmp_id);
 
     result = (atom->pid != INVALID_PATTERN_ID);
 
diff --git a/src/analysis/scan/patterns/tokens/atom.h b/src/analysis/scan/patterns/tokens/atom.h
index 2fbc19e..1d912d7 100644
--- a/src/analysis/scan/patterns/tokens/atom.h
+++ b/src/analysis/scan/patterns/tokens/atom.h
@@ -29,7 +29,6 @@
 
 
 #include "../backend.h"
-#include "../../context.h"
 #include "../../../../arch/vmpa.h"
 #include "../../../../common/bits.h"
 #include "../../../../common/szstr.h"
@@ -43,11 +42,14 @@ typedef struct _tracked_scan_atom_t
     phys_t len;                             /* Taille de ladite sélection  */
     phys_t rem;                             /* Reste après l'atome         */
 
+    bool fast_check;                        /* Besoin de vérifications ?   */
+
+    uint32_t tmp_id[2];                     /* Couple d'identifiants temp. */
+
     patid_t pid;                            /* Identifiant de la bribe     */
 
 } tracked_scan_atom_t;
 
-
 /* Note l'intêret de rechercher un octet particulier. */
 int rate_byte_quality(bin_t, bitfield_t *, size_t *);
 
@@ -60,11 +62,24 @@ void find_best_atom(const sized_binary_t *, size_t , tracked_scan_atom_t *, size
 /* Etablit la liste des cas de figures ignorant la casse. */
 sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, const tracked_scan_atom_t *, size_t);
 
-/* Etablit la liste des cas de figures avec un octet partiel. */
-sized_binary_t *make_atoms_from_masked_byte(bin_t, bin_t, size_t *);
+/* Mémorisation d'un octet visé avec son masque */
+typedef struct _masked_byte_t
+{
+    bin_t value;                            /* Valeur de l'octet visé      */
+    bin_t mask;                             /* Masque à appliquer          */
+
+} masked_byte_t;
+
+#define MASK_MAX_LEN_FOR_ATOMS 2
+
+/* Etablit la liste des cas de figures avec des octets partiels. */
+sized_binary_t *make_atoms_from_masked_bytes(const masked_byte_t *, size_t, size_t *);
+
+/* Amorce l'insertion de l'atome déterminé d'une série d'octets. */
+bool enroll_prepared_atom(const sized_binary_t *, GEngineBackend *, tracked_scan_atom_t *);
 
-/* Enregistre l'atome déterminé d'une série d'octets. */
-bool enroll_prepared_atom(const sized_binary_t *, GScanContext *, GEngineBackend *, tracked_scan_atom_t *);
+/* Récupère un identifiant final pour un atome d'octets. */
+bool build_atom_pattern_id(tracked_scan_atom_t *, GEngineBackend *);
 
 
 
diff --git a/src/analysis/scan/patterns/tokens/node-int.h b/src/analysis/scan/patterns/tokens/node-int.h
index 091a5be..520e2a4 100644
--- a/src/analysis/scan/patterns/tokens/node-int.h
+++ b/src/analysis/scan/patterns/tokens/node-int.h
@@ -28,9 +28,9 @@
 #include "node.h"
 
 
-#include "offset.h"
-
 
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+typedef float (* compute_scan_token_node_weight_fc) (const GScanTokenNode *);
 
 /* Prend acte d'une nouvelle propriété pour le noeud. */
 typedef void (* apply_scan_token_node_flags_fc) (GScanTokenNode *, ScanTokenNodeFlags);
@@ -38,23 +38,30 @@ typedef void (* apply_scan_token_node_flags_fc) (GScanTokenNode *, ScanTokenNode
 /* Noeuds clefs de l'arborescence mise en place */
 typedef struct _scan_tree_points_t
 {
-    GScanTokenNode *first_node;             /* Premier noeud de traitement */
-    GScanTokenNode *last_node;              /* Dernier noeud de traitement */
-
     GScanTokenNode *first_plain;            /* Premier noeud textuel       */
     GScanTokenNode *best_masked;            /* Noeud masqué le plus long   */
 
 } scan_tree_points_t;
 
-
 /* Parcourt une arborescence de noeuds et y relève des éléments. */
 typedef void (* visit_scan_token_node_fc) (GScanTokenNode *, scan_tree_points_t *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
+typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+typedef bool (* build_scan_token_node_id_fc) (GScanTokenNode *, GEngineBackend *);
+
+typedef enum _TokenNodeCheckFlags
+{
+    TNCF_UPDATE_IN_PLACE = (1 << 0),        /* Actualisation de l'entrée   */
+    TNCF_CREATE_NEW      = (1 << 1),        /* Allocation de positions     */
+    TNCF_KEEP_DISCARDED  = (1 << 2),        /* Inversion des résultats     */
+
+} TokenNodeCheckFlags;
 
 /* Transforme les correspondances locales en trouvailles. */
-typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 /* Décomposition d'un motif de recherche en atomes (instance) */
@@ -71,10 +78,12 @@ struct _GScanTokenNodeClass
 {
     GObjectClass parent;                    /* A laisser en premier        */
 
+    compute_scan_token_node_weight_fc compute_weight; /* Evaluation        */
+    visit_scan_token_node_fc visit;         /* Phase de répérage initial   */
     apply_scan_token_node_flags_fc apply;   /* Prise en compte de fanions  */
 
-    visit_scan_token_node_fc visit;         /* Phase de répérage initial   */
     enroll_scan_token_node_fc enroll;       /* Inscription d'un motif      */
+    build_scan_token_node_id_fc build_id;   /* Récupération d'identifiant  */
 
     check_scan_token_node_fc check_forward; /* Conversion en trouvailles   */
     check_scan_token_node_fc check_backward;/* Conversion en trouvailles   */
@@ -86,13 +95,13 @@ struct _GScanTokenNodeClass
 void g_scan_token_node_visit(GScanTokenNode *, scan_tree_points_t *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-bool _g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
+bool _g_scan_token_node_enroll(GScanTokenNode *, GEngineBackend *, size_t, size_t *);
 
 /* Transforme les correspondances locales en trouvailles. */
-void _g_scan_token_node_check_forward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+void _g_scan_token_node_check_forward(const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 /* Transforme les correspondances locales en trouvailles. */
-void _g_scan_token_node_check_backward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+void _g_scan_token_node_check_backward(const GScanTokenNode *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 
diff --git a/src/analysis/scan/patterns/tokens/node.c b/src/analysis/scan/patterns/tokens/node.c
index 71fcf05..767cc6d 100644
--- a/src/analysis/scan/patterns/tokens/node.c
+++ b/src/analysis/scan/patterns/tokens/node.c
@@ -143,6 +143,38 @@ static void g_scan_token_node_finalize(GScanTokenNode *node)
 *                                                                             *
 *  Paramètres  : node = noeud de motif à consulter.                           *
 *                                                                             *
+*  Description : Communique l'intérêt d'un noeud au sein d'une analyse.       *
+*                                                                             *
+*  Retour      : Poids de l'importance pour un départ de scan.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+float g_scan_token_node_compute_weight_for_scan(const GScanTokenNode *node)
+{
+    float result;                           /* Valeur à retourner          */
+    GScanTokenNodeClass *class;             /* Classe de l'instance        */
+
+    class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+    if (class->compute_weight != NULL)
+        result = class->compute_weight(node);
+    else
+        result = 0;
+
+    return result;
+
+}
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node = noeud de motif à consulter.                           *
+*                                                                             *
 *  Description : Indique les propriétés particulières d'un noeud d'analyse.   *
 *                                                                             *
 *  Retour      : Propriétés particulières associées au noeud.                 *
@@ -206,15 +238,6 @@ void g_scan_token_node_visit(GScanTokenNode *node, scan_tree_points_t *points)
 {
     GScanTokenNodeClass *class;             /* Classe de l'instance        */
 
-    if (node->flags & STNF_PROD)
-    {
-        if (points->first_node == NULL)
-            points->first_node = node;
-
-        points->last_node = node;
-
-    }
-
     class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
 
     if (class->visit != NULL)
@@ -243,9 +266,6 @@ bool g_scan_token_node_setup_tree(GScanTokenNode *node)
 
     /* Phase de localisation */
 
-    points.first_node = NULL;
-    points.last_node = NULL;
-
     points.first_plain = NULL;
     points.best_masked = NULL;
 
@@ -253,9 +273,8 @@ bool g_scan_token_node_setup_tree(GScanTokenNode *node)
 
     /* Phase d'application */
 
-    // TODO : REMME
-    //g_scan_token_node_set_flags(points.first_node, STNF_FIRST);
-    //g_scan_token_node_set_flags(points.last_node, STNF_LAST);
+    g_scan_token_node_set_flags(node, STNF_FIRST);
+    g_scan_token_node_set_flags(node, STNF_LAST);
 
     if (points.first_plain != NULL)
         main = points.first_plain;
@@ -264,11 +283,11 @@ bool g_scan_token_node_setup_tree(GScanTokenNode *node)
         main = points.best_masked;
 
     else
-        main = node;//points.first_node;
+        main = node;
 
     g_scan_token_node_set_flags(main, STNF_MAIN);
 
-    result = (main != node/*points.first_node*/);
+    result = (main != node);
 
     return result;
 
@@ -278,7 +297,6 @@ bool g_scan_token_node_setup_tree(GScanTokenNode *node)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : node    = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                maxsize = taille max. des atomes (mise en commun optimisée). *
 *                slow    = niveau de ralentissement induit (0 = idéal). [OUT] *
@@ -291,14 +309,14 @@ bool g_scan_token_node_setup_tree(GScanTokenNode *node)
 *                                                                             *
 ******************************************************************************/
 
-bool _g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+bool _g_scan_token_node_enroll(GScanTokenNode *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
     GScanTokenNodeClass *class;             /* Classe de l'instance        */
 
     class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
 
-    result = class->enroll(node, context, backend, maxsize, slow);
+    result = class->enroll(node, backend, maxsize, slow);
 
     return result;
 
@@ -308,7 +326,6 @@ bool _g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEng
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : node    = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                maxsize = taille max. des atomes (mise en commun optimisée). *
 *                slow    = niveau de ralentissement induit (0 = idéal). [OUT] *
@@ -321,7 +338,7 @@ bool _g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEng
 *                                                                             *
 ******************************************************************************/
 
-bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+bool g_scan_token_node_enroll(GScanTokenNode *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
 
@@ -329,7 +346,37 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
 
     *slow = 0;
 
-    result = _g_scan_token_node_enroll(node, context, backend, maxsize, slow);
+    result = _g_scan_token_node_enroll(node, backend, maxsize, slow);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node    = définition de la bribe à peaufiner.                *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère un identifiant final pour un atome d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_node_build_id(GScanTokenNode *node, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+    GScanTokenNodeClass *class;             /* Classe de l'instance        */
+
+    class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+    if (class->build_id == NULL)
+        result = true;
+    else
+        result = class->build_id(node, backend);
 
     return result;
 
@@ -338,13 +385,10 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -354,7 +398,7 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
 *                                                                             *
 ******************************************************************************/
 
-void _g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+void _g_scan_token_node_check_forward(const GScanTokenNode *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
     GScanTokenNodeClass *class;             /* Classe de l'instance        */
 
@@ -366,17 +410,15 @@ void _g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *
 
     class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
 
-    class->check_forward(node, context, content, matches, offset, not, skip);
+    class->check_forward(node, params, cflags, skip);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -386,9 +428,9 @@ void _g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+void g_scan_token_node_check_forward(const GScanTokenNode *node, scan_node_check_params_t *params)
 {
-    node_search_offset_t offset;            /* Espace des correspondances  */
+    node_search_offset_t offset;            /* Espace des correspondances  */ 
     bool skip;                              /* Mise en attente des analyses*/
     size_t ocount;                          /* Quantité de bornes présentes*/
     node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
@@ -401,11 +443,14 @@ void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *c
     const node_offset_range_t *range;       /* Bornes d'espace à parcourir */
     phys_t new_end;                         /* Nouveau point d'arrivée     */
 
-    init_node_search_offset(&offset);
+    init_node_search_offset(&params->offset);
 
     skip = true;
 
-    _g_scan_token_node_check_forward(node, context, content, matches, &offset, false, &skip);
+    _g_scan_token_node_check_forward(node, params, TNCF_UPDATE_IN_PLACE, &skip);
+
+
+#if 0   // FIXME
 
     /**
      * Si un décalage entre octets n'a pas été consommé,
@@ -425,8 +470,41 @@ void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *c
          * phase d'extension des résultats inexistants est ainsi sautée.
          */
         if (count_pending_matches(matches) == 0)
+        {
+
+
+            for (o = 0; o < ocount; o++)
+            {
+                range = (*ranges_ptr) + o;
+
+
+                printf("range: %u - %u\n",
+                       (unsigned int)range->min,
+                       (unsigned int)range->max);
+
+
+                /*
+                new_end = old_end + range->min;
+
+                if (new_end > matches->content_end)
+                    new_end = matches->content_end;
+
+                add_pending_match(pending_matches_t *, phys_t, phys_t);
+
+                extend_pending_match_ending(matches, p, new_end);
+                */
+
+            }
+
+
+
+
+
+
             goto offset_done;
 
+        }
+
         reset_pending_matches_ttl(matches);
 
         pending_ptr = get_all_pending_matches(matches, &pcount);
@@ -466,20 +544,19 @@ void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *c
 
     assert(offset.used == 0);
 
-    exit_node_search_offset(&offset);
+#endif
+
+    exit_node_search_offset(&params->offset);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -489,13 +566,13 @@ void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *c
 *                                                                             *
 ******************************************************************************/
 
-void _g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+void _g_scan_token_node_check_backward(const GScanTokenNode *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
     GScanTokenNodeClass *class;             /* Classe de l'instance        */
 
     class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
 
-    class->check_backward(node, context, content, matches, offset, not, skip);
+    class->check_backward(node, params, cflags, skip);
 
     if (node->flags & STNF_MAIN)
     {
@@ -508,10 +585,8 @@ void _g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -521,7 +596,7 @@ void _g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+void g_scan_token_node_check_backward(const GScanTokenNode *node, scan_node_check_params_t *params)
 {
     node_search_offset_t offset;            /* Espace des correspondances  */
     bool skip;                              /* Mise en attente des analyses*/
@@ -536,11 +611,13 @@ void g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *
     const node_offset_range_t *range;       /* Bornes d'espace à parcourir */
     phys_t new_start;                       /* Nouveau point d'arrivée     */
 
-    init_node_search_offset(&offset);
+    init_node_search_offset(&params->offset);
 
     skip = true;
 
-    _g_scan_token_node_check_backward(node, context, content, matches, &offset, false, &skip);
+    _g_scan_token_node_check_backward(node, params, TNCF_UPDATE_IN_PLACE, &skip);
+
+#if 0 // FIXME
 
     /**
      * Si un décalage entre octets n'a pas été consommé,
@@ -591,6 +668,8 @@ void g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *
 
     assert(offset.used == 0);
 
-    exit_node_search_offset(&offset);
+#endif
+
+    exit_node_search_offset(&params->offset);
 
 }
diff --git a/src/analysis/scan/patterns/tokens/node.h b/src/analysis/scan/patterns/tokens/node.h
index a2e3b0d..55bf0a8 100644
--- a/src/analysis/scan/patterns/tokens/node.h
+++ b/src/analysis/scan/patterns/tokens/node.h
@@ -29,9 +29,10 @@
 #include <stdbool.h>
 
 
+#include "offset.h"
 #include "../backend.h"
 #include "../../context.h"
-#include "../../matches/pending.h"
+#include "../../matches/bytes.h"
 
 
 #define G_TYPE_SCAN_TOKEN_NODE            g_scan_token_node_get_type()
@@ -53,10 +54,9 @@ typedef struct _GScanTokenNodeClass GScanTokenNodeClass;
 typedef enum _ScanTokenNodeFlags
 {
     STNF_NONE  = (0 << 0),                  /* Absence de singularité      */
-    STNF_PROD  = (1 << 0),                  /* Absence de singularité      */
-    STNF_FIRST = (1 << 1),                  /* Premier noeud de traitement */   /* REMME ? */
-    STNF_LAST  = (1 << 2),                  /* Dernier noeud de traitement */   /* REMME ? */
-    STNF_MAIN  = (1 << 3),                  /* Point de départ d'analyse   */
+    STNF_FIRST = (1 << 0),                  /* Premier noeud de traitement */
+    STNF_LAST  = (1 << 1),                  /* Dernier noeud de traitement */
+    STNF_MAIN  = (1 << 2),                  /* Point de départ d'analyse   */
 
 } ScanTokenNodeFlags;
 
@@ -64,6 +64,11 @@ typedef enum _ScanTokenNodeFlags
 /* Indique le type défini pour un élément décomposant un motif d'octets à rechercher. */
 GType g_scan_token_node_get_type(void);
 
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+float g_scan_token_node_compute_weight_for_scan(const GScanTokenNode *);
+
+
+
 /* Indique les propriétés particulières d'un noeud d'analyse. */
 ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *);
 
@@ -74,13 +79,47 @@ void g_scan_token_node_set_flags(GScanTokenNode *, ScanTokenNodeFlags);
 bool g_scan_token_node_setup_tree(GScanTokenNode *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-bool g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
+bool g_scan_token_node_enroll(GScanTokenNode *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+bool g_scan_token_node_build_id(GScanTokenNode *, GEngineBackend *);
+
+/* Accès direct aux éléments utiles aux contrôles */
+typedef struct _scan_node_check_params_t
+{
+    GScanContext *context;                  /* Contexte de scan en cours   */
+    GBinContent *content;                   /* Contenu binaire associé     */
+    GUMemSlice *allocator;                  /* Allocateur pour zones       */
+
+    phys_t content_start;                   /* Point de début du contenu   */
+    phys_t content_end;                     /* Point de fin du contenu     */
+
+    node_search_offset_t offset;            /* Décalages à respecter       */
+
+    bool initialized;                       /* Etat du suivi               */
+
+    /* TNCF_UPDATE_IN_PLACE */
+
+    match_area_t *main_areas;               /* Zones principales à analyser*/
+    size_t main_count;                      /* Taille de cette liste       */
+
+    /* TNCF_CREATE_NEW */
+
+    match_area_t *created_areas;            /* Zones principales à analyser*/
+    size_t created_count;                   /* Taille de cette liste       */
+
+    /* TNCF_KEEP_DISCARDED */
+
+    match_area_t *kept_areas;               /* Zones principales à analyser*/
+    size_t kept_count;                      /* Taille de cette liste       */
+
+} scan_node_check_params_t;
 
 /* Transforme les correspondances locales en trouvailles. */
-void g_scan_token_node_check_forward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
+void g_scan_token_node_check_forward(const GScanTokenNode *, scan_node_check_params_t *);
 
 /* Transforme les correspondances locales en trouvailles. */
-void g_scan_token_node_check_backward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
+void g_scan_token_node_check_backward(const GScanTokenNode *, scan_node_check_params_t *);
 
 
 
diff --git a/src/analysis/scan/patterns/tokens/nodes/any.c b/src/analysis/scan/patterns/tokens/nodes/any.c
index 6233cb4..10a01cd 100644
--- a/src/analysis/scan/patterns/tokens/nodes/any.c
+++ b/src/analysis/scan/patterns/tokens/nodes/any.c
@@ -55,10 +55,10 @@ static void g_scan_token_node_any_finalize(GScanTokenNodeAny *);
 static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *, GScanContext *, GEngineBackend *, size_t, size_t *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 
@@ -95,6 +95,7 @@ static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass)
 
     node = G_SCAN_TOKEN_NODE_CLASS(klass);
 
+    node->apply = (apply_scan_token_node_flags_fc)NULL;
     node->visit = (visit_scan_token_node_fc)NULL;
     node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_any_enroll;
     node->check_forward = (check_scan_token_node_fc)g_scan_token_node_any_check_forward;
@@ -117,8 +118,6 @@ static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass)
 
 static void g_scan_token_node_any_init(GScanTokenNodeAny *any)
 {
-    g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(any), STNF_PROD);
-
     any->min = 0;
     any->has_max = false;
 
@@ -297,13 +296,10 @@ static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GScanContext *
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -313,66 +309,250 @@ static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GScanContext *
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
-    bool initialized;                       /* Initialisation du suivi ?   */
+    ScanTokenNodeFlags flags;               /* Particularités du noeud     */
     bool forced;                            /* Inclusion dans un scan ?    */
     phys_t size;                            /* Quantité d'octets considérés*/
-    const phys_t *datasize;                 /* Taille max. à communiquer   */
+    phys_t match_size;                      /* Taille de correspondance    */
+    phys_t i;                               /* Boucle de parcours #1       */
+    match_area_t *space;                    /* Nouvelle zone à intégrer    */
+    match_area_t *area;                     /* Correspondance à valider    */
+    match_area_t *next;                     /* Correspondance suivante     */
+    phys_t after;                           /* Espace disposible après     */
+    phys_t min_end;                         /* Fin la plus proche possible */
+    phys_t max_end;                         /* Fin la plus éloignée trouvée*/
+    bool updated;                           /* Existence de correspondance */
+    size_t rcount;                          /* Quantité de bornes présentes*/
+    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */
+    size_t r;                               /* Boucle de parcours #2       */
+    phys_t updated_edge;                    /* Nouvelle bordure de motif   */
+    match_area_t *new_area;                 /* Copie de correspondance     */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
 
     if (*skip)
         return;
 
+    flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node));
 
-    //         $a = { [1-3] 6f }
-    // pas d'initialisation, construction de résultats avec une taille nulle
+    forced = (flags & STNF_MAIN);
 
+    assert((!params->initialized && forced) || (params->initialized & !forced));
+
+    /**
+     * La situation forcée correspond au cas particulier d'une définition
+     * complètement abstraite : ??, ?? ??, etc.
+     */
+    if (forced)
+    {
+        size = params->content_end - params->content_start;
 
+        if (node->has_max && 0 /* greedy ? */)
+        {
+            match_size = node->max;
 
-    initialized = are_pending_matches_initialized(matches);
+            if (match_size > size)
+                match_size = node->min;
 
-    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+        }
+        else
+            match_size = node->min;
+
+        /**
+         * Si le contenu binaire est trop petit pour contenir au moins un enregistrement,
+         * aucune correspondance n'est enregistrée. Comme le noeud est le principale, ie.
+         * seul et unique, l'analyse s'arrête ensuite d'elle même.
+         *
+         * Si le contenu binaire est suffisamment large, des espaces sont créés et l'analyse
+         * se termine ensuite. La conservation des espaces n'est donc pas utile, ni réalisée.
+         */
 
-    size = matches->content_end - matches->content_start;
+        if (match_size <= size)
+        {
+            size -= match_size;
 
-    datasize = (not ? &size : NULL);
+            assert(cflags & TNCF_UPDATE_IN_PLACE);
 
-    if (forced)
-    {
-        assert(!initialized);
+            for (i = 0; i < size; i++)
+            {
+                space = g_umem_slice_alloc(params->allocator);
 
-        if (node->min > size)
-            /* TODO set abort in matches */;
+                space->start = params->content_start + i;
+                space->end = space->start + match_size;
 
-        else
-            add_range_to_node_search_offset(offset,
-                                            matches->content_start,
-                                            matches->content_end - matches->content_start,
-                                            datasize);
+                add_tail_match_area(space, &params->main_areas);
+                params->main_count++;
+
+            }
+
+        }
 
     }
+
+    /**
+     * Situation usuelle : des espaces séparent deux noeuds.
+     */
     else
     {
-        assert(initialized);
+        assert(params->initialized);
+
+        /**
+         * Les espaces existants sont à compléter. La présence de tels espaces
+         * restant à traiter peut provenir d'un aiguillage imposé par un motif
+         * tel que :
+         *
+         *    ( aa ?? ?? | bb cc dd ) [0-5] ee ee
+         *
+         * Deux espaces sont à considérer avant de rechercher des octets ee :
+         * [2-7] et [0-5].
+         *
+         * Note : ces espaces peuvent être disjoints.
+         *
+         * Si aucun espace n'est en place, un est créé.
+         */
 
+        extend_node_search_offset(&params->offset, node->min, node->max, node->has_max);
 
-        // TODO : compléter les intervales éventuels déjà en place
+        /**
+         * Si un décalage enregistré ne peut être consommé par un noeud, les
+         * résultats sont étendus ici à minima ou maxima.
+         */
 
+        if (flags & STNF_LAST)
+        {
+            assert(offsets_exist(&params->offset));
 
-        /*
-        printf("[i] create hole: %llx <-> %llx\n",
-               (unsigned long long)node->min,
-               (unsigned long long)node->max);
-        */
+            if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
 
+            for_each_match_area_safe(area, &params->main_areas, next)
+            {
+                assert(area->end <= params->content_end);
 
-        if (node->has_max)
-            add_range_to_node_search_offset(offset, node->min, node->max, datasize);
-        else
-            add_range_to_node_search_offset(offset, node->min, matches->content_end - node->min, datasize);
+                after = params->content_end - area->end;
+
+                if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
 
-        // TODO : si dernier, virer les correspondances qui n'ont plus l'espace de fin requis
-        // -> au niveau du noeud, en fonction du flag _LAST
+                min_end = params->content_end;
+                max_end = params->content_start;
+
+                updated = false;
+
+                ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+                for (r = 0; r < rcount; r++)
+                {
+                    if (ranges[r].min > after)
+                        continue;
+
+                    updated_edge = area->end + ranges[r].min;
+
+                    if (updated_edge < min_end)
+                        min_end = updated_edge;
+
+                    if (ranges[r].has_max)
+                    {
+                        if (ranges[r].max > after)
+                            updated_edge = params->content_end;
+                        else
+                            updated_edge = area->end + ranges[r].max;
+
+                        if (updated_edge > max_end)
+                            max_end = updated_edge;
+
+                    }
+
+                    updated = true;
+
+                }
+
+                if (updated)
+                {
+                    /**
+                     * Si seuls les rejets sont d'intérêt, les correspondances établies
+                     * ne se voient pas mises à jours ni retirées.
+                     */
+
+                    if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+                    {
+                        if (cflags & TNCF_UPDATE_IN_PLACE)
+                            area->end = (1 /* greedy */ ? min_end : max_end);
+
+                        else if (cflags & TNCF_CREATE_NEW)
+                        {
+                            new_area = g_umem_slice_alloc(params->allocator);
+
+                            *new_area = *area;
+
+                            new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+                            add_tail_match_area(new_area, &params->created_areas);
+                            params->created_count++;
+
+                        }
+
+#ifndef NDEBUG
+                        else
+                            assert(false);
+#endif
+
+                    }
+
+                }
+
+                else
+                {
+                    /**
+                     * Si la liste principale doit être mise à jour...
+                     */
+
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                    {
+                        del_match_area(area, &params->main_areas);
+                        assert(params->main_count > 0);
+                        params->main_count--;
+                    }
+
+                    /**
+                     * Au cas où le rejet est d'intérêt, l'absence de correspondance
+                     * est conservée dans une liste dédiée.
+                     */
+
+                    if (cflags & TNCF_KEEP_DISCARDED)
+                    {
+                        if (cflags & TNCF_UPDATE_IN_PLACE)
+                        {
+                            add_tail_match_area(area, &params->kept_areas);
+                            params->kept_count++;
+                        }
+
+                        else if (cflags & TNCF_CREATE_NEW)
+                        {
+                            new_area = g_umem_slice_alloc(params->allocator);
+
+                            *new_area = *area;
+
+                            new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+                            add_tail_match_area(new_area, &params->kept_areas);
+                            params->kept_count++;
+
+                        }
+
+#ifndef NDEBUG
+                        else
+                            assert(false);
+#endif
+
+                    }
+
+                }
+
+            }
+
+            disable_all_ranges_in_node_search_offset(&params->offset);
+
+        }
 
     }
 
@@ -381,13 +561,10 @@ static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, G
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -397,55 +574,191 @@ static void g_scan_token_node_any_check_forward(const GScanTokenNodeAny *node, G
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_any_check_backward(const GScanTokenNodeAny *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
+    ScanTokenNodeFlags flags;               /* Particularités du noeud     */
 #ifndef NDEBUG
     bool forced;                            /* Inclusion dans un scan ?    */
 #endif
-    phys_t size;                            /* Quantité d'octets considérés*/
-    const phys_t *datasize;                 /* Taille max. à communiquer   */
+    match_area_t *area;                     /* Correspondance à valider    */
+    match_area_t *next;                     /* Correspondance suivante     */
+    phys_t before;                          /* Espace disposible avant     */
+    phys_t min_start;                       /* Début le plus proche trouvé */
+    phys_t max_start;                       /* Début le plus distant trouvé*/
+    bool updated;                           /* Existence de correspondance */
+    size_t rcount;                          /* Quantité de bornes présentes*/
+    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */
+    size_t r;                               /* Boucle de parcours          */
+    phys_t updated_edge;                    /* Nouvelle bordure de motif   */
+    match_area_t *new_area;                 /* Copie de correspondance     */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
 
     if (*skip)
         return;
 
     /**
      * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
-     * du sens de lecteur normal). Donc l'initialisation a déjà dû avoir lieu.
+     * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.
      */
-    assert(are_pending_matches_initialized(matches));
+
+    assert(params->initialized);
+
+    flags = g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node));
 
     /**
      * Si les recherches associées au noeud ont été forcées, alors les traitements
      * liés ont déjà été effectués, et l'appel de cette fonction aurait dû être sauté.
      */
 #ifndef NDEBUG
-    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+    forced = (flags & STNF_MAIN);
     assert(!forced);
 #endif
 
-    size = matches->content_end - matches->content_start;
+    /**
+     * Les considérations pour l'extension des espaces en place sont identiques
+     * à celles formulées dans la fonction g_scan_token_node_any_check_forward().
+     */
 
-    if (node->min > size)
-        /* TODO set abort in matches */;
+    extend_node_search_offset(&params->offset, node->min, node->max, node->has_max);
 
-    else
+    /**
+     * Si un décalage enregistré ne peut être consommé par un noeud, les
+     * résultats sont étendus ici à minima ou maxima.
+     */
+
+    if (flags & STNF_FIRST)
     {
-        datasize = (not ? &size : NULL);
+        assert(offsets_exist(&params->offset));
 
-        /**
-         * Une tolérance basée sur des espaces (et non des positions) est déterminée
-         * ici.
-         *
-         * Charge au prochain noeud de traitement de filtrer les résultats courants
-         * avec, voire à la fonction _g_scan_token_node_check_backward() de
-         * réaliser une synthèse finale si le noeud courant est le dernier d'une
-         * lignée.
-         */
+        if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
 
-        if (node->has_max)
-            add_range_to_node_search_offset(offset, node->min, node->max, datasize);
-        else
-            add_range_to_node_search_offset(offset, node->min, matches->content_end - node->min, datasize);
+        for_each_match_area_safe(area, &params->main_areas, next)
+        {
+            assert(params->content_start <= area->start);
+
+            before = area->start - params->content_start;
+
+            if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+            min_start = params->content_start;
+            max_start = params->content_end;
+
+            updated = false;
+
+            ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+            for (r = 0; r < rcount; r++)
+            {
+                if (ranges[r].min > before)
+                    continue;
+
+                updated_edge = area->start - ranges[r].min;
+
+                if (updated_edge > min_start)
+                    min_start = updated_edge;
+
+                if (ranges[r].has_max)
+                {
+                    if (ranges[r].max > before)
+                        updated_edge = params->content_start;
+                    else
+                        updated_edge = area->start - ranges[r].max;
+
+                    if (updated_edge < max_start)
+                        max_start = updated_edge;
+
+                }
+
+                updated = true;
+
+            }
+
+            if (updated)
+            {
+                /**
+                 * Si seuls les rejets sont d'intérêt, les correspondances établies
+                 * ne se voient pas mises à jours ni retirées.
+                 */
+
+                if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                        area->start = (1 /* greedy */ ? min_start : max_start);
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+                        add_tail_match_area(new_area, &params->created_areas);
+                        params->created_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
+                }
+
+            }
+
+            else
+            {
+                /**
+                 * Si la liste principale doit être mise à jour...
+                 */
+
+                if (cflags & TNCF_UPDATE_IN_PLACE)
+                {
+                    del_match_area(area, &params->main_areas);
+                    assert(params->main_count > 0);
+                    params->main_count--;
+                }
+
+                /**
+                 * Au cas où le rejet est d'intérêt, l'absence de correspondance
+                 * est conservée dans une liste dédiée.
+                 */
+
+                if (cflags & TNCF_KEEP_DISCARDED)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                    {
+                        add_tail_match_area(area, &params->kept_areas);
+                        params->kept_count++;
+                    }
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+                        add_tail_match_area(new_area, &params->kept_areas);
+                        params->kept_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
+                }
+
+            }
+
+        }
+
+        disable_all_ranges_in_node_search_offset(&params->offset);
 
     }
 
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.c b/src/analysis/scan/patterns/tokens/nodes/choice.c
index df6ae45..102c7de 100644
--- a/src/analysis/scan/patterns/tokens/nodes/choice.c
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.c
@@ -24,6 +24,9 @@
 #include "choice.h"
 
 
+#include <assert.h>
+
+
 #include "choice-int.h"
 
 
@@ -48,6 +51,9 @@ static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *);
 /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
 
 
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+static float g_scan_token_node_choice_compute_weight_for_scan(const GScanTokenNodeChoice *);
+
 /* Prend acte d'une nouvelle propriété pour le noeud. */
 static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTokenNodeFlags);
 
@@ -55,13 +61,16 @@ static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTok
 static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *, scan_tree_points_t *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *, GScanContext *, GEngineBackend *, size_t, size_t *);
+static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_choice_build_id(GScanTokenNodeChoice *, GEngineBackend *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 
@@ -98,9 +107,11 @@ static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *klass
 
     node = G_SCAN_TOKEN_NODE_CLASS(klass);
 
+    node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_choice_compute_weight_for_scan;
     node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_choice_apply_flags;
     node->visit = (visit_scan_token_node_fc)g_scan_token_node_choice_visit;
     node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_choice_enroll;
+    node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_choice_build_id;
     node->check_forward = (check_scan_token_node_fc)g_scan_token_node_choice_check_forward;
     node->check_backward = (check_scan_token_node_fc)g_scan_token_node_choice_check_backward;
 
@@ -227,6 +238,51 @@ void g_scan_token_node_choice_add(GScanTokenNodeChoice *choice, GScanTokenNode *
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : node = noeud de motif à consulter.                           *
+*                                                                             *
+*  Description : Communique l'intérêt d'un noeud au sein d'une analyse.       *
+*                                                                             *
+*  Retour      : Poids de l'importance pour un départ de scan.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static float g_scan_token_node_choice_compute_weight_for_scan(const GScanTokenNodeChoice *node)
+{
+    float result;                           /* Valeur à retourner          */
+    size_t weight_count;                    /* Nombre de comptabilisations */
+    size_t i;                               /* Boucle de parcours          */
+    float weight;                           /* Nouveau poids à intégrer    */
+
+    result = 0;
+
+    weight_count = 0;
+
+    for (i = 0; i < node->count; i++)
+    {
+        weight = g_scan_token_node_compute_weight_for_scan(node->children[i]);
+
+        if (weight > 0)
+        {
+            result += weight;
+            weight_count++;
+        }
+
+    }
+
+    if (weight_count != node->count)
+        result = 0;
+    else
+        result /= weight_count;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : node  = noeud de motif à mettre à jour.                      *
 *                flags = propriétés particulières à associer au noeud.        *
 *                                                                             *
@@ -274,9 +330,6 @@ static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree
 
     for (i = 0; i < node->count; i++)
     {
-        tmp_points.first_node = NULL;
-        tmp_points.last_node = NULL;
-
         tmp_points.first_plain = NULL;
         tmp_points.best_masked = NULL;
 
@@ -296,7 +349,6 @@ static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : node    = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                maxsize = taille max. des atomes (mise en commun optimisée). *
 *                slow    = niveau de ralentissement induit (0 = idéal). [OUT] *
@@ -309,7 +361,7 @@ static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
     size_t i;                               /* Boucle de parcours          */
@@ -317,7 +369,7 @@ static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanCon
     result = true;
 
     for (i = 0; i < node->count && result; i++)
-        result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow);
+        result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow);
 
     return result;
 
@@ -326,13 +378,38 @@ static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanCon
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node    = définition de la bribe à peaufiner.                *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère un identifiant final pour un atome d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_choice_build_id(GScanTokenNodeChoice *node, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+    size_t i;                               /* Boucle de parcours #1       */
+
+    result = true;
+
+    for (i = 0; i < node->count && result; i++)
+        result = g_scan_token_node_build_id(node->children[i], backend);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -342,78 +419,117 @@ static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanCon
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
-    pending_matches_t init_matches;         /* Correspondances initiales   */
-    node_search_offset_t init_offset;       /* Intervales initiaux         */ 
-    size_t new_offset;                      /* Décompte d'intervales       */
+    bool initialized;                       /* Initialisation du suivi ?   */
+    match_area_t *collected_areas;          /* Zones mises en place ici    */
+    size_t collected_count;                 /* Quantité de ces zones       */
+    TokenNodeCheckFlags local_cflags;       /* Particularités nouvelles    */
     size_t i;                               /* Boucle de parcours          */
-    pending_matches_t tmp_matches;          /* Copie locale de travail #1  */
-    node_search_offset_t tmp_offset;        /* Copie locale de travail #2  */
+    scan_node_check_params_t local_params;  /* Rassemblement de paramètres */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
 
     if (*skip)
         return;
 
-    /* Copie des contextes de départ */
+    /* Lancement des sous-traitements */
 
-    copy_pending_matches(&init_matches, matches);
+    initialized = false;
 
-    exit_pending_matches(matches);
-    init_pending_matches(matches, &init_matches.content_start, &init_matches.content_end);
+    collected_areas = NULL;
+    collected_count = 0;
 
-    copy_node_search_offset(&init_offset, offset);
+    local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW;
 
-    exit_node_search_offset(offset);
-    init_node_search_offset(offset);
+    for (i = 0; i < node->count; i++)
+    {
+        local_params = *params;
 
-    /* Lancement des sous-traitements */
+        local_params.created_areas = NULL;
+        local_params.created_count = 0;
 
-    new_offset = 0;
+        local_params.kept_areas = NULL;
+        local_params.kept_count = 0;
 
-    for (i = 0; i < node->count; i++)
-    {
-        copy_pending_matches(&tmp_matches, &init_matches);
-        copy_node_search_offset(&tmp_offset, &init_offset);
+        if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count)
+            local_cflags = cflags;
+
+        _g_scan_token_node_check_forward(node->children[i], &local_params, local_cflags, skip);
 
-        _g_scan_token_node_check_forward(node->children[i], context, content,
-                                         &tmp_matches, &tmp_offset, not, skip);
+        initialized |= local_params.initialized;
 
-        merge_pending_matches(matches, &tmp_matches);
-        merge_node_search_offset(offset, &tmp_offset);
+        if (local_cflags & TNCF_KEEP_DISCARDED)
+        {
+            merge_match_areas(&collected_areas, &local_params.kept_areas);
+            collected_count += local_params.kept_count;
+        }
 
-        if (tmp_offset.used > 0)
-            new_offset++;
+        else if (local_cflags & TNCF_CREATE_NEW)
+        {
+            merge_match_areas(&collected_areas, &local_params.created_areas);
+            collected_count += local_params.created_count;
+        }
 
-        exit_pending_matches(&tmp_matches);
-        exit_node_search_offset(&tmp_offset);
+        else
+        {
+            assert(local_cflags & TNCF_UPDATE_IN_PLACE);
+
+            merge_match_areas(&collected_areas, &local_params.main_areas);
+            collected_count += local_params.main_count;
+
+        }
 
     }
 
-    /* Sortie propre */
+    /* Enregistrement des résultats finaux */
 
-    exit_pending_matches(&init_matches);
-    exit_node_search_offset(&init_offset);
+    if (collected_count > 1)
+        sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL);
 
-    /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+    if (0x1) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count);
 
-    if (new_offset != node->count)
+    params->initialized = initialized;
+
+    if (cflags & TNCF_KEEP_DISCARDED)
     {
-        assert(node->count > 1);
-        add_range_to_node_search_offset(offset, 0, 0, NULL);
+        params->kept_areas = collected_areas;
+        params->kept_count = collected_count;
     }
 
+    else if (cflags & TNCF_CREATE_NEW)
+    {
+        params->created_areas = collected_areas;
+        params->created_count = collected_count;
+    }
+
+    else
+    {
+        assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+        params->main_areas = collected_areas;
+        params->main_count = collected_count;
+
+    }
+
+
+
+
+
+    /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python)
+
+
+
+
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offsets = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -423,64 +539,108 @@ static void g_scan_token_node_choice_check_forward(const GScanTokenNodeChoice *n
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_choice_check_backward(const GScanTokenNodeChoice *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
-    pending_matches_t init_matches;         /* Correspondances initiales   */
-    node_search_offset_t init_offset;       /* Intervales initiaux         */ 
-    size_t new_offset;                      /* Décompte d'intervales       */
+    match_area_t *collected_areas;          /* Zones mises en place ici    */
+    size_t collected_count;                 /* Quantité de ces zones       */
+    TokenNodeCheckFlags local_cflags;       /* Particularités nouvelles    */
     size_t i;                               /* Boucle de parcours          */
-    pending_matches_t tmp_matches;          /* Copie locale de travail #1  */
-    node_search_offset_t tmp_offset;        /* Copie locale de travail #2  */
+    scan_node_check_params_t local_params;  /* Rassemblement de paramètres */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
 
     if (*skip)
         return;
 
-    /* Copie des contextes de départ */
+    /**
+     * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+     * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.
+     */
 
-    copy_pending_matches(&init_matches, matches);
-
-    exit_pending_matches(matches);
-    init_pending_matches(matches, &init_matches.content_start, &init_matches.content_end);
-
-    copy_node_search_offset(&init_offset, offset);
-
-    exit_node_search_offset(offset);
-    init_node_search_offset(offset);
+    assert(params->initialized);
 
     /* Lancement des sous-traitements */
 
-    new_offset = 0;
+    collected_areas = NULL;
+    collected_count = 0;
+
+    local_cflags = (cflags & ~TNCF_UPDATE_IN_PLACE) | TNCF_CREATE_NEW;
 
     for (i = 0; i < node->count; i++)
     {
-        copy_pending_matches(&tmp_matches, &init_matches);
-        copy_node_search_offset(&tmp_offset, &init_offset);
+        local_params = *params;
+
+        local_params.created_areas = NULL;
+        local_params.created_count = 0;
+
+        local_params.kept_areas = NULL;
+        local_params.kept_count = 0;
+
+        if ((cflags & TNCF_CREATE_NEW) == 0 && (i + 1) == node->count)
+            local_cflags = cflags;
 
-        _g_scan_token_node_check_backward(node->children[i], context, content,
-                                          &tmp_matches, &tmp_offset, not, skip);
+        _g_scan_token_node_check_backward(node->children[i], &local_params, local_cflags, skip);
 
-        merge_pending_matches(matches, &tmp_matches);
-        merge_node_search_offset(offset, &tmp_offset);
+        if (local_cflags & TNCF_KEEP_DISCARDED)
+        {
+            merge_match_areas(&collected_areas, &local_params.kept_areas);
+            collected_count += local_params.kept_count;
+        }
 
-        if (tmp_offset.used > 0)
-            new_offset++;
+        else if (local_cflags & TNCF_CREATE_NEW)
+        {
+            merge_match_areas(&collected_areas, &local_params.created_areas);
+            collected_count += local_params.created_count;
+        }
 
-        exit_pending_matches(&tmp_matches);
-        exit_node_search_offset(&tmp_offset);
+        else
+        {
+            assert(local_cflags & TNCF_UPDATE_IN_PLACE);
+
+            merge_match_areas(&collected_areas, &local_params.main_areas);
+            collected_count += local_params.main_count;
+
+        }
 
     }
 
-    /* Sortie propre */
+    /* Enregistrement des résultats finaux */
 
-    exit_pending_matches(&init_matches);
-    exit_node_search_offset(&init_offset);
+    if (collected_count > 1)
+        sort_match_areas_no_dup(&collected_areas, &collected_count, compare_match_area_as_dl_item, NULL);
 
-    /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+    if (0x1) printf("[%s] collected: #%zu (bis)\n", __FUNCTION__, collected_count);
 
-    if (new_offset != node->count)
+    if (cflags & TNCF_KEEP_DISCARDED)
     {
-        assert(node->count > 1);
-        add_range_to_node_search_offset(offset, 0, 0, NULL);
+        params->kept_areas = collected_areas;
+        params->kept_count = collected_count;
     }
 
+    else if (cflags & TNCF_CREATE_NEW)
+    {
+        params->created_areas = collected_areas;
+        params->created_count = collected_count;
+    }
+
+    else
+    {
+        assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+        params->main_areas = collected_areas;
+        params->main_count = collected_count;
+
+    }
+
+
+
+
+
+    /// TODO : gestion des offets en sortie : ajout (+ ajout d'un test en Python)
+
+
+
+
+
+
 }
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked-int.h b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
index 9eb8712..5fcc330 100644
--- a/src/analysis/scan/patterns/tokens/nodes/masked-int.h
+++ b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
@@ -41,8 +41,9 @@ struct _GScanTokenNodeMasked
     size_t len;                             /* Taille de cette série       */
 
     sized_binary_t *raw;                    /* Liste de motifs à couvrir   */
-    tracked_scan_atom_t *atoms;             /* Atomes correspondants       */
-    size_t count;                           /* Taille de cette liste       */
+    size_t raw_count;                       /* Taille de cette liste       */
+
+    tracked_scan_atom_t *enrolled_atoms;    /* Atomes correspondants       */
     size_t enrolled_count;                  /* Quantité avec identifiant   */
 
 };
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.c b/src/analysis/scan/patterns/tokens/nodes/masked.c
index 8765b1d..2dbdb08 100644
--- a/src/analysis/scan/patterns/tokens/nodes/masked.c
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.c
@@ -56,16 +56,19 @@ static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *);
 static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *, scan_tree_points_t *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *, GScanContext *, GEngineBackend *, size_t, size_t *);
+static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_masked_build_id(GScanTokenNodeMasked *, GEngineBackend *);
 
 /* Détermine si un contenu d'intérêt est présent à une position. */
 static bool check_scan_token_node_masked_content(const masked_byte_t *, size_t, phys_t, GBinContent *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 
@@ -102,8 +105,10 @@ static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *klass
 
     node = G_SCAN_TOKEN_NODE_CLASS(klass);
 
+    node->apply = (apply_scan_token_node_flags_fc)NULL;
     node->visit = (visit_scan_token_node_fc)g_scan_token_node_masked_visit;
     node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_masked_enroll;
+    node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_masked_build_id;
     node->check_forward = (check_scan_token_node_fc)g_scan_token_node_masked_check_forward;
     node->check_backward = (check_scan_token_node_fc)g_scan_token_node_masked_check_backward;
 
@@ -124,14 +129,14 @@ static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *klass
 
 static void g_scan_token_node_masked_init(GScanTokenNodeMasked *masked)
 {
-    g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(masked), STNF_PROD);
-
     masked->bytes = NULL;
     masked->len = 0;
 
     masked->raw = NULL;
-    masked->atoms = NULL;
-    masked->count = 0;
+    masked->raw_count = 0;
+
+    masked->enrolled_atoms = NULL;
+    masked->enrolled_count = 0;
 
 }
 
@@ -174,14 +179,14 @@ static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *masked)
     if (masked->bytes != NULL)
         free(masked->bytes);
 
-    for (i = 0; i < masked->count; i++)
+    for (i = 0; i < masked->raw_count; i++)
         exit_szstr(&masked->raw[i]);
 
     if (masked->raw != NULL)
         free(masked->raw);
 
-    if (masked->atoms != NULL)
-        free(masked->atoms);
+    if (masked->enrolled_atoms != NULL)
+        free(masked->enrolled_atoms);
 
     G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->finalize(G_OBJECT(masked));
 
@@ -305,7 +310,6 @@ static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : node    = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                maxsize = taille max. des atomes (mise en commun optimisée). *
 *                slow    = niveau de ralentissement induit (0 = idéal). [OUT] *
@@ -318,7 +322,7 @@ static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
     bool forced;                            /* Inclusion dans un scan ?    */
@@ -333,6 +337,8 @@ static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanCon
     {
         *slow += (maxsize * 2);
 
+        node->raw = make_atoms_from_masked_bytes(node->bytes, node->len, &node->raw_count);
+
         /**
          * Dans le cas bien précis de l'usage de l'algorithme Bitap pour les recherches
          * dans le contenu binaire à analyser, on tire parti du coût nul des recherches
@@ -353,19 +359,23 @@ static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanCon
 
         else
         {
-            node->raw = make_atoms_from_masked_byte(node->bytes[0].value, node->bytes[0].mask, &node->count);
+            node->enrolled_atoms = malloc(node->raw_count * sizeof(tracked_scan_atom_t));
+            node->enrolled_count = node->raw_count;
 
-            node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t));
-
-            for (i = 0; i < node->count && result; i++)
+            for (i = 0; i < node->enrolled_count && result; i++)
             {
-                find_best_atom(&node->raw[i], maxsize, &node->atoms[i], NULL);
+                find_best_atom(&node->raw[i], maxsize, &node->enrolled_atoms[i], NULL);
 
-                result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]);
+                /**
+                 * Correction : si l'atome ne représente qu'une vue partielle,
+                 * la validation rapide ne peut s'appliquer.
+                 */
+                if (node->enrolled_atoms[i].fast_check)
+                    node->enrolled_atoms[i].fast_check = (node->enrolled_atoms[i].len == node->len);
 
-            }
+                result = enroll_prepared_atom(&node->raw[i], backend, &node->enrolled_atoms[i]);
 
-            node->enrolled_count = node->count;
+            }
 
         }
 
@@ -378,6 +388,34 @@ static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanCon
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : node    = définition de la bribe à peaufiner.                *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère un identifiant final pour un atome d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_masked_build_id(GScanTokenNodeMasked *node, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+    size_t i;                               /* Boucle de parcours #1       */
+
+    result = true;
+
+    for (i = 0; i < node->enrolled_count && result; i++)
+        result = build_atom_pattern_id(&node->enrolled_atoms[i], backend);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : bytes   = octets partiels avec leur masque à interpréter.    *
 *                len     = quantité d'octets à interpréter.                   *
 *                start   = point d'analyse à respecter.                       *
@@ -419,13 +457,10 @@ static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, siz
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -435,37 +470,36 @@ static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, siz
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
-    bool initialized;                       /* Initialisation du suivi ?   */
 #ifndef NDEBUG
     bool forced;                            /* Inclusion dans un scan ?    */
 #endif
-    size_t ocount;                          /* Quantité de bornes présentes*/
-    node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
     size_t i;                               /* Boucle de parcours #1       */
     const tracked_scan_atom_t *atom;        /* Atome correspondant         */
-    size_t count;                           /* Quantité de bribes trouvées */
-    const phys_t *found;                    /* Localisations des bribes    */
-    size_t k;                               /* Boucle de parcours #2       */
-    phys_t new_begin;                       /* Nouveau départ à tester     */
-    size_t o;                               /* Boucle de parcours #3       */
-    const node_offset_range_t *range;       /* Bornes d'espace à parcourir */
+    GUMemSlice *atoms;                      /* Localisations des bribes    */
+    const umem_slice_iter_t *aiter;         /* Boucle de parcours #2       */
+    match_area_t *end;                      /* Borne de fin de parcours    */
+    match_area_t *pos;                      /* Position courante           */
     bool status;                            /* Bilan d'une correspondance  */
-    size_t pcount;                          /* Nombre de correspondances   */
-    match_area_t * const *pending_ptr;      /* Correspondances actuelles   */
-    size_t p;                               /* Boucle de parcours #4       */
-    match_area_t *pending;                  /* Correspondance à traiter    */
+    match_area_t *area;                     /* Correspondance à valider    */
+    match_area_t *next;                     /* Correspondance suivante     */
     phys_t after;                           /* Espace disposible après     */
-    phys_t min;                             /* Borne minimale déterminée   */
-    phys_t max;                             /* Borne maximale déterminée   */
-    phys_t j;                               /* Boucle de parcours #5       */
+    phys_t min_end;                         /* Fin la plus proche possible */
+    phys_t max_end;                         /* Fin la plus éloignée trouvée*/
+    bool updated;                           /* Existence de correspondance */
+    size_t rcount;                          /* Quantité de bornes présentes*/
+    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */
+    size_t r;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t p;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t updated_edge;                    /* Nouvelle bordure de motif   */
+    match_area_t *new_area;                 /* Copie de correspondance     */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
 
     if (*skip)
         return;
 
-    initialized = are_pending_matches_initialized(matches);
-
     /**
      * Si l'analyse arrive à un ou plusieurs octets masqués, soit il s'agit du
      * premier noeud, et la génération d'atomes a été forcée pour obtenir des
@@ -475,61 +509,103 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n
      */
 #ifndef NDEBUG
     forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
-    assert((!initialized && forced) || (initialized && (!forced || not)));
+    assert((!params->initialized && forced) || (params->initialized && (!forced || cflags & TNCF_KEEP_DISCARDED)));
 #endif
 
-    ranges_ptr = get_node_search_offset_ranges(offset, &ocount);
-
-    /* Si aucune correspondance n'a été établie */
-    if (!initialized)
+    if (!params->initialized)
     {
         for (i = 0; i < node->enrolled_count; i++)
         {
-            atom = &node->atoms[i];
+            atom = &node->enrolled_atoms[i];
 
-            found = g_scan_context_get_atom_matches(context, atom->pid, &count);
+            atoms = g_scan_context_get_atom_matches(params->context, atom->pid);
 
-            for (k = 0; k < count; k++)
+            if (atom->fast_check)
             {
-                assert(atom->pos == 0);
+                for (aiter = g_umem_slice_get_iter(atoms); aiter != NULL; aiter = aiter->next)
+                {
+                    end = aiter->data_end;
 
-                new_begin = found[k];
+                    for (pos = aiter->data; pos < end; pos++)
+                    {
+                        /**
+                         * La modification de la zone d'origine est possible dans tous les cas
+                         * car cette zone a été allouée de façon dédiée à un type de correspondances
+                         * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+                         */
+                        pos->end = pos->start + atom->len;
 
-                /**
-                 * Si des bornes sont spécifiées, la position de l'atome est testée.
-                 *
-                 * Dans la pratique, cette situation (non initialisée) ne peut provenir
-                 * que d'un espace situé dans le vide, donc couvrant un large périmètre.
-                 * La validation a ainsi de grandes chances de passer...
-                 *
-                 * Le motif pouvant amener à cette situation (pas d'initialisation,
-                 * mais à décalage à considérer) est par exemple :
-                 *
-                 *    ~( ?? ?1 )
-                 *
-                 */
-                if (ocount > 0)
-                {
-                    if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin))
-                        continue;
-                }
+                        if (cflags & TNCF_KEEP_DISCARDED)
+                        {
+                            add_tail_match_area(pos, &params->kept_areas);
+                            params->kept_count++;
+                        }
 
-                /**
-                 * Existe-t-il assez de place pour faire tenir le motif masqué ?
-                 */
-                if ((new_begin + node->len) > matches->content_end)
-                    continue;
+                        else if (cflags & TNCF_CREATE_NEW)
+                        {
+                            add_tail_match_area(pos, &params->created_areas);
+                            params->created_count++;
+                        }
+
+                        else
+                        {
+                            assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+                            add_tail_match_area(pos, &params->main_areas);
+                            params->main_count++;
 
-                status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+                        }
+
+                    }
 
-                if ((status && !not) || (!status && not))
+                }
+
+            }
+
+            else
+            {
+                for (aiter = g_umem_slice_get_iter(atoms); aiter != NULL; aiter = aiter->next)
                 {
-                    /**
-                     * Il ne peut y avoir qu'une seule séquence d'octets à un même
-                     * emplacement, donc le couple (start, len) enregistré est
-                     * unique.
-                     */
-                    add_pending_match(matches, new_begin, node->len);
+                    end = aiter->data_end;
+
+                    for (pos = aiter->data; pos < end; pos++)
+                    {
+                        status = check_scan_token_node_masked_content(node->bytes, node->len,
+                                                                      pos->start, params->content);
+
+                        if (status)
+                        {
+                            /**
+                             * La modification de la zone d'origine est possible dans tous les cas
+                             * car cette zone a été allouée de façon dédiée à un type de correspondances
+                             * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+                             */
+                            pos->end = pos->start + node->len;
+
+                            if (cflags & TNCF_KEEP_DISCARDED)
+                            {
+                                add_tail_match_area(pos, &params->kept_areas);
+                                params->kept_count++;
+                            }
+
+                            else if (cflags & TNCF_CREATE_NEW)
+                            {
+                                add_tail_match_area(pos, &params->created_areas);
+                                params->created_count++;
+                            }
+
+                            else
+                            {
+                                assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+                                add_tail_match_area(pos, &params->main_areas);
+                                params->main_count++;
+
+                            }
+
+                        }
+
+                    }
 
                 }
 
@@ -539,69 +615,77 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n
 
     }
 
-    /* Si les correspondances en place sont à confirmer et compléter */
+    /**
+     * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+     * des comparaisons entières de motifs.
+     */
     else
     {
-        reset_pending_matches_ttl(matches);
+        if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
 
-        pending_ptr = get_all_pending_matches(matches, &pcount);
-
-        for (p = 0; p < pcount; p++)
+        for_each_match_area_safe(area, &params->main_areas, next)
         {
-            pending = (*pending_ptr) + p;
+            assert(area->end <= params->content_end);
+
+            after = params->content_end - area->end;
 
-            assert(pending->end <= matches->content_end);
+            if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+            /**
+             * S'il s'avère qu'il existe de multiples correspondances dans l'espace
+             * analysé, c'est la prise en compte d'une éventuelle avarice quant aux
+             * distances consommées qui va sélectionner la position d'une bribe de
+             * correspondance retenue.
+             *
+             * Par exemple, deux correspondances '?1 ?1 [1-3] ?2 ?2' peuvent être
+             * valides pour un même contenu :
+             *
+             *    aa.bbb -> correspondance 'aa.bb'
+             *      ^
+             *
+             *    aa.bbb -> correspondance 'aa..bb'
+             *      ^
+             */
 
-            after = matches->content_end - pending->end;
+            min_end = params->content_end;
+            max_end = params->content_start;
 
-            new_begin = pending->end;
+            updated = false;
 
-            if (ocount > 0)
+            /* Souplesse dans les positions ? */
+            if (offsets_exist(&params->offset))
             {
-                for (o = 0; o < ocount; o++)
+                ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
+
+                for (r = 0; r < rcount; r++)
                 {
-                    range = (*ranges_ptr) + o;
-
-                    /**
-                     * Si bornes de tolérance il y a, l'espace restant est validé en
-                     * tenant compte de ces bornes.
-                     */
-                    if (!get_node_offset_range(range, node->len, after, &min, &max))
-                        continue;
-
-                    /**
-                     * Une recherche des différentes correspondances amont est lancée.
-                     */
-                    for (j = min; j <= max; j++)
+                    assert(ranges[r].has_max);
+                    assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+                    for (p = ranges[r].min; p <= ranges[r].max; p++)
                     {
+                        /**
+                         * Si la fin d'une correspondance potentielle est trop près de
+                         * la fin du contenu binaire et ne peut contenir le motif
+                         * représenté, alors la corresponance est écartée sans appel.
+                         */
+                        if ((p + node->len) > after)
+                            break;
+
                         status = check_scan_token_node_masked_content(node->bytes, node->len,
-                                                                      new_begin + j, content);
+                                                                      area->end + p, params->content);
 
-                        if ((status && !not) || (!status && not))
+                        if (status)
                         {
-                            /**
-                             * S'il s'avère qu'il existe de multiples correspondances dans l'espace
-                             * analysé, c'est la fonction extend_pending_match_ending() qui
-                             * duplique cette correspondance, en s'appuyant sur le TTL pour
-                             * repérer ce cas de figure.
-                             *
-                             * Par exemple, deux correspondances '?1 ?1 [1-3] ?2 ?2'
-                             * sont valides pour un même contenu :
-                             *
-                             *    aa.bbb -> correspondance 'aa.bb'
-                             *      ^
-                             *
-                             *    aa.bbb -> correspondance 'aa..bb'
-                             *      ^
-                             */
-                            extend_pending_match_ending(matches, p, new_begin + j + node->len);
+                            updated_edge = area->end + p + node->len;
 
-                            /**
-                             * Comme l'extension a pu conduire à un ajout et donc à une
-                             * réallocation de la liste, on recharge l'élément pour les
-                             * itérations suivantes.
-                             */
-                            pending = (*pending_ptr) + p;
+                            if (updated_edge < min_end)
+                                min_end = updated_edge;
+
+                            if (updated_edge > max_end)
+                                max_end = updated_edge;
+
+                            updated = true;
 
                         }
 
@@ -611,55 +695,133 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n
 
             }
 
+            /* Position immédiatement attendue */
             else
             {
                 /**
                  * Si la fin d'une correspondance potentielle est trop près de
                  * la fin du contenu binaire et ne peut contenir le motif
-                 * représenté, alors la corresponance est écartée.
+                 * représenté, alors la corresponance est écartée sans appel.
                  */
-                if (node->len > after)
-                    continue;
+                if (node->len <= after)
+                {
+                    status = check_scan_token_node_masked_content(node->bytes, node->len,
+                                                                  area->end, params->content);
+
+                    if (status)
+                    {
+                        updated_edge = area->end + node->len;
+
+                        min_end = updated_edge;
+                        max_end = updated_edge;
+
+                        updated = true;
+
+                    }
+
+                }
 
-                new_begin = pending->end;
+            }
 
-                status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+            if (updated)
+            {
+                /**
+                 * Si seuls les rejets sont d'intérêt, les correspondances établies
+                 * ne se voient pas mises à jours ni retirées.
+                 */
 
-                if ((status && !not) || (!status && not))
+                if ((cflags & TNCF_KEEP_DISCARDED) == 0)
                 {
-                    extend_pending_match_ending(matches, p, new_begin + node->len);
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                        area->end = (1 /* greedy */ ? min_end : max_end);
 
-                    /**
-                     * Comme il n'y a qu'une seule itération par correspondance,
-                     * nul besoin de recharcher l'élément.
-                     */
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+                        add_tail_match_area(new_area, &params->created_areas);
+                        params->created_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
 
                 }
 
             }
 
-        }
+            else
+            {
+                /**
+                 * Si la liste principale doit être mise à jour...
+                 */
 
-        purge_pending_matches(matches);
+                if (cflags & TNCF_UPDATE_IN_PLACE)
+                {
+                    del_match_area(area, &params->main_areas);
+                    assert(params->main_count > 0);
+                    params->main_count--;
+                }
+
+                /**
+                 * Au cas où le rejet est d'intérêt, l'absence de correspondance
+                 * est conservée dans une liste dédiée.
+                 */
+
+                if (cflags & TNCF_KEEP_DISCARDED)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                    {
+                        add_tail_match_area(area, &params->kept_areas);
+                        params->kept_count++;
+                    }
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+                        add_tail_match_area(new_area, &params->kept_areas);
+                        params->kept_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
+                }
+
+            }
+
+        }
 
     }
 
-    set_pending_matches_initialized(matches);
+    params->initialized = true;
 
-    disable_all_ranges_in_node_search_offset(offset);
+    disable_all_ranges_in_node_search_offset(&params->offset);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offsets = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -669,26 +831,32 @@ static void g_scan_token_node_masked_check_forward(const GScanTokenNodeMasked *n
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
 #ifndef NDEBUG
     bool forced;                            /* Inclusion dans un scan ?    */
 #endif
-    size_t pcount;                          /* Nombre de correspondances   */
-    match_area_t * const *pending_ptr;      /* Correspondances actuelles   */
-    size_t ocount;                          /* Quantité de bornes présentes*/
-    node_offset_range_t * const *ranges_ptr;/* Bornes d'espace à parcourir */
-    size_t p;                               /* Boucle de parcours #1       */
-    const match_area_t *pending;            /* Correspondance à traiter    */
-    phys_t before;                          /* Espace disposible avant     */
-    phys_t new_begin;                       /* Nouveau départ à tester     */
-    size_t o;                               /* Boucle de parcours #2       */
-    const node_offset_range_t *range;       /* Bornes d'espace à parcourir */
-    phys_t min;                             /* Borne minimale déterminée   */
-    phys_t max;                             /* Borne maximale déterminée   */
-    phys_t j;                               /* Boucle de parcours #3       */
+
+
+
     bool status;                            /* Bilan d'une correspondance  */
 
+
+    match_area_t *area;                     /* Correspondance à valider    */
+    match_area_t *next;                     /* Correspondance suivante     */
+    phys_t before;                          /* Espace disposible avant     */
+    phys_t min_start;                       /* Début le plus proche trouvé */
+    phys_t max_start;                       /* Début le plus distant trouvé*/
+    bool updated;                           /* Existence de correspondance */
+    size_t rcount;                          /* Quantité de bornes présentes*/
+    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */
+    size_t r;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t p;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t updated_edge;                    /* Nouvelle bordure de motif   */
+    match_area_t *new_area;                 /* Copie de correspondance     */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
     if (*skip)
         return;
 
@@ -696,7 +864,7 @@ static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *
      * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
      * du sens de lecteur normal). Donc l'initialisation a déjà dû avoir lieu.
      */
-    assert(are_pending_matches_initialized(matches));
+    assert(params->initialized);
 
     /**
      * Si les recherches associées au noeud ont été forcées, alors les traitements
@@ -707,65 +875,121 @@ static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *
     assert(!forced);
 #endif
 
-    reset_pending_matches_ttl(matches);
 
-    pending_ptr = get_all_pending_matches(matches, &pcount);
 
-    ranges_ptr = get_node_search_offset_ranges(offset, &ocount);
 
-    for (p = 0; p < pcount; p++)
+    /**
+     * .............
+     */
+    if (0)
     {
-        pending = (*pending_ptr) + p;
 
-        assert(matches->content_start <= pending->start);
 
-        before = pending->start - matches->content_start;
+        ;
+
+
 
-        new_begin = pending->start - node->len;
+    }
+
+    /**
+     * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+     * des comparaisons entières de motifs.
+     */
+    else
+    {
+        if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
 
-        if (ocount > 0)
+        for_each_match_area_safe(area, &params->main_areas, next)
         {
-            for (o = 0; o < ocount; o++)
+            assert(params->content_start <= area->start);
+
+            before = area->start - params->content_start;
+
+            if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+            /**
+             * Il ne peut y avoir qu'une seule séquence d'octets à un même
+             * emplacement. En revanche, des modificateurs peuvent construire
+             * possédant une même base, mais offrant des suffixes différents
+             * (par exemple, un marqueur nul UTF-16 final en complément).
+             *
+             * L'ensemble des combinaisons produites doit ainsi être exploré.
+             */
+
+            min_start = params->content_start;
+            max_start = params->content_end;
+
+            updated = false;
+
+            /* Souplesse dans les positions ? */
+            if (offsets_exist(&params->offset))
             {
-                range = (*ranges_ptr) + o;
+                ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
 
-                /**
-                 * Si bornes de tolérance il y a, l'espace restant est validé en
-                 * tenant compte de ces bornes.
-                 */
-                if (!get_node_offset_range(range, node->len, before, &min, &max))
+                for (r = 0; r < rcount; r++)
                 {
-                    if (not)
-                        extend_pending_match_beginning(matches, p, pending->start - node->len);
+                    assert(ranges[r].has_max);
+                    assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+                    for (p = ranges[r].min; p <= ranges[r].max; p++)
+                    {
+                        /**
+                         * Si la fin d'une correspondance potentielle est trop près de
+                         * la fin du contenu binaire et ne peut contenir le motif
+                         * représenté, alors la corresponance est écartée sans appel.
+                         */
+                        if ((p + node->len) > before)
+                            break;
+
+                        status = check_scan_token_node_masked_content(node->bytes, node->len,
+                                                                      area->start - node->len - p,
+                                                                      params->content);
+
+                        if (status)
+                        {
+                            updated_edge = area->start - node->len - p;
+
+                            if (updated_edge > min_start)
+                                min_start = updated_edge;
+
+                            if (updated_edge < max_start)
+                                max_start = updated_edge;
+
+                            updated = true;
 
-                    continue;
+                        }
+
+                    }
 
                 }
 
+            }
+
+            /* Position immédiatement attendue */
+            else
+            {
                 /**
-                 * Une recherche des différentes correspondances amont est lancée.
+                 * Si la fin d'une correspondance potentielle est trop près du
+                 * début du contenu binaire et ne peut contenir le motif
+                 * représenté, alors la corresponance est écartée sans appel.
                  */
-                for (j = min; j <= max; j++)
+                if (node->len <= before)
                 {
                     status = check_scan_token_node_masked_content(node->bytes, node->len,
-                                                                  new_begin - j, content);
+                                                                  area->start - node->len,
+                                                                  params->content);
 
-                    if ((status && !not) || (!status && not))
+                    if (status)
                     {
-                        /**
-                         * S'il s'avère qu'il existe de multiples correspondances dans l'espace
-                         * analysé, c'est la fonction extend_pending_match_beginning() qui
-                         * duplique cette correspondance, en s'appuyant sur le TTL pour
-                         * repérer ce cas de figure.
-                         */
-                        extend_pending_match_beginning(matches, p, new_begin);
+                        updated_edge = area->start - node->len;
 
-                        /**
-                         * Comme l'extension a pu conduire à un ajout et donc à une
-                         * réallocation de la liste, on recharge l'élément pour les
-                         * itérations suivantes.
-                         */
-                        pending = (*pending_ptr) + p;
+                        if (updated_edge > min_start)
+                            min_start = updated_edge;
+
+                        if (updated_edge < max_start)
+                            max_start = updated_edge;
+
+                        updated = true;
 
                     }
 
@@ -773,35 +997,92 @@ static void g_scan_token_node_masked_check_backward(const GScanTokenNodeMasked *
 
             }
 
-        }
-
-        else
-        {
-            /**
-             * Si le début d'une correspondance potentielle est trop près du début
-             * du contenu binaire et ne peut contenir le motif représenté, alors
-             * la corresponance est écartée.
-             */
-            if (node->len > before)
+            if (updated)
             {
-                if (not)
-                    extend_pending_match_beginning(matches, p, new_begin);
+                /**
+                 * Si seuls les rejets sont d'intérêt, les correspondances établies
+                 * ne se voient pas mises à jours ni retirées.
+                 */
+
+                if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                        area->start = (1 /* greedy */ ? min_start : max_start);
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+                        add_tail_match_area(new_area, &params->created_areas);
+                        params->created_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
 
-                continue;
+                }
 
             }
 
-            status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+            else
+            {
+                /**
+                 * Si la liste principale doit être mise à jour...
+                 */
+
+                if (cflags & TNCF_UPDATE_IN_PLACE)
+                {
+                    del_match_area(area, &params->main_areas);
+                    assert(params->main_count > 0);
+                    params->main_count--;
+                }
+
+                /**
+                 * Au cas où le rejet est d'intérêt, l'absence de correspondance
+                 * est conservée dans une liste dédiée.
+                 */
 
-            if ((status && !not) || (!status && not))
-                extend_pending_match_beginning(matches, p, new_begin);
+                if (cflags & TNCF_KEEP_DISCARDED)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                    {
+                        add_tail_match_area(area, &params->kept_areas);
+                        params->kept_count++;
+                    }
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+                        add_tail_match_area(new_area, &params->kept_areas);
+                        params->kept_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
+                }
+
+            }
 
         }
 
     }
 
-    purge_pending_matches(matches);
-
-    disable_all_ranges_in_node_search_offset(offset);
+    disable_all_ranges_in_node_search_offset(&params->offset);
 
 }
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.h b/src/analysis/scan/patterns/tokens/nodes/masked.h
index d1765fa..04a05bc 100644
--- a/src/analysis/scan/patterns/tokens/nodes/masked.h
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.h
@@ -49,15 +49,6 @@ typedef struct _GScanTokenNodeMasked GScanTokenNodeMasked;
 typedef struct _GScanTokenNodeMaskedClass GScanTokenNodeMaskedClass;
 
 
-/* Mémorisation d'un octet visé avec son masque */
-typedef struct _masked_byte_t
-{
-    bin_t value;                            /* Valeur de l'octet visé      */
-    bin_t mask;                             /* Masque à appliquer          */
-
-} masked_byte_t;
-
-
 /* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */
 GType g_scan_token_node_masked_get_type(void);
 
diff --git a/src/analysis/scan/patterns/tokens/nodes/not.c b/src/analysis/scan/patterns/tokens/nodes/not.c
index 645a1c8..81fce28 100644
--- a/src/analysis/scan/patterns/tokens/nodes/not.c
+++ b/src/analysis/scan/patterns/tokens/nodes/not.c
@@ -24,6 +24,9 @@
 #include "not.h"
 
 
+#include <assert.h>
+
+
 #include "not-int.h"
 
 
@@ -48,17 +51,23 @@ static void g_scan_token_node_not_finalize(GScanTokenNodeNot *);
 /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
 
 
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+static void g_scan_token_node_not_apply_flags(GScanTokenNodeNot *, ScanTokenNodeFlags);
+
 /* Parcourt une arborescence de noeuds et y relève des éléments. */
 static void g_scan_token_node_not_visit(GScanTokenNodeNot *, scan_tree_points_t *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *, GScanContext *, GEngineBackend *, size_t, size_t *);
+static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_not_build_id(GScanTokenNodeNot *, GEngineBackend *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 
@@ -95,8 +104,10 @@ static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *klass)
 
     node = G_SCAN_TOKEN_NODE_CLASS(klass);
 
+    node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_not_apply_flags;
     node->visit = (visit_scan_token_node_fc)g_scan_token_node_not_visit;
     node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_not_enroll;
+    node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_not_build_id;
     node->check_forward = (check_scan_token_node_fc)g_scan_token_node_not_check_forward;
     node->check_backward = (check_scan_token_node_fc)g_scan_token_node_not_check_backward;
 
@@ -223,6 +234,26 @@ bool g_scan_token_node_not_create(GScanTokenNodeNot *not, GScanTokenNode *child)
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : node  = noeud de motif à mettre à jour.                      *
+*                flags = propriétés particulières à associer au noeud.        *
+*                                                                             *
+*  Description : Prend acte d'une nouvelle propriété pour le noeud.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_not_apply_flags(GScanTokenNodeNot *node, ScanTokenNodeFlags flags)
+{
+    g_scan_token_node_set_flags(node->child, flags);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : node   = point de départ du parcours à effectuer.            *
 *                points = points capitaux de l'arborescence. [OUT]            *
 *                                                                             *
@@ -244,7 +275,6 @@ static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_point
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : node    = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                maxsize = taille max. des atomes (mise en commun optimisée). *
 *                slow    = niveau de ralentissement induit (0 = idéal). [OUT] *
@@ -257,11 +287,11 @@ static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_point
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
 
-    result = _g_scan_token_node_enroll(node->child, context, backend, maxsize, slow);
+    result = _g_scan_token_node_enroll(node->child, backend, maxsize, slow);
 
     return result;
 
@@ -270,13 +300,34 @@ static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GScanContext *
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node    = définition de la bribe à peaufiner.                *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère un identifiant final pour un atome d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_not_build_id(GScanTokenNodeNot *node, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+
+    result = g_scan_token_node_build_id(node->child, backend);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -286,8 +337,12 @@ static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GScanContext *
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
+
+#if 0
+
+
     bool initialized;                       /* Initialisation du suivi ?   */
     phys_t i;                               /* Boucle de parcours          */
 
@@ -322,7 +377,7 @@ static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, G
     _g_scan_token_node_check_forward(node->child, context, content, matches, offset, !not, skip);
 
 
-
+#endif
 
 
 }
@@ -330,13 +385,10 @@ static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, G
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -346,7 +398,7 @@ static void g_scan_token_node_not_check_forward(const GScanTokenNodeNot *node, G
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_not_check_backward(const GScanTokenNodeNot *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
 
 
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c
index 71f5f17..166ce74 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.c
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.c
@@ -52,20 +52,26 @@ static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *);
 /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
 
 
+/* Communique l'intérêt d'un noeud au sein d'une analyse. */
+static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *);
+
 /* Parcourt une arborescence de noeuds et y relève des éléments. */
 static void g_scan_token_node_plain_visit(GScanTokenNodePlain *, scan_tree_points_t *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GScanContext *, GEngineBackend *, size_t, size_t *);
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *, GEngineBackend *);
 
 /* Détermine si un contenu d'intérêt est présent à une position. */
 static bool check_scan_token_node_plain_content(const sized_binary_t *, const tracked_scan_atom_t *, bool, phys_t, GBinContent *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 
@@ -102,8 +108,11 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
 
     node = G_SCAN_TOKEN_NODE_CLASS(klass);
 
+    node->compute_weight = (compute_scan_token_node_weight_fc)g_scan_token_node_plain_compute_weight_for_scan;
+    node->apply = (apply_scan_token_node_flags_fc)NULL;
     node->visit = (visit_scan_token_node_fc)g_scan_token_node_plain_visit;
     node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_plain_enroll;
+    node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_plain_build_id;
     node->check_forward = (check_scan_token_node_fc)g_scan_token_node_plain_check_forward;
     node->check_backward = (check_scan_token_node_fc)g_scan_token_node_plain_check_backward;
 
@@ -124,8 +133,6 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
 
 static void g_scan_token_node_plain_init(GScanTokenNodePlain *plain)
 {
-    g_scan_token_node_set_flags(G_SCAN_TOKEN_NODE(plain), STNF_PROD);
-
     init_szstr(&plain->orig);
     plain->modifier = NULL;
     plain->flags = SPNF_NONE;
@@ -314,6 +321,29 @@ char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *node,
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : node = noeud de motif à consulter.                           *
+*                                                                             *
+*  Description : Communique l'intérêt d'un noeud au sein d'une analyse.       *
+*                                                                             *
+*  Retour      : Poids de l'importance pour un départ de scan.                *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static float g_scan_token_node_plain_compute_weight_for_scan(const GScanTokenNodePlain *node)
+{
+    float result;                           /* Valeur à retourner          */
+
+    result = node->orig.len;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : node   = point de départ du parcours à effectuer.            *
 *                points = points capitaux de l'arborescence. [OUT]            *
 *                                                                             *
@@ -327,9 +357,25 @@ char *g_scan_token_node_plain_get_modifier_path(const GScanTokenNodePlain *node,
 
 static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_points_t *points)
 {
+    GScanTokenNode *candidate;              /* Autre version du noeud      */
+    float node_weight;                      /* Poids du noeud courant      */
+    float other_weight;                     /* Poids de l'autre noeud      */
+
     if (points->first_plain == NULL)
         points->first_plain = G_SCAN_TOKEN_NODE(node);
 
+    else
+    {
+        candidate = G_SCAN_TOKEN_NODE(node);
+
+        node_weight = g_scan_token_node_compute_weight_for_scan(candidate);
+        other_weight = g_scan_token_node_compute_weight_for_scan(points->first_plain);
+
+        if (node_weight >= other_weight)
+            points->first_plain = candidate;
+
+    }
+
 }
 
 
@@ -349,7 +395,7 @@ static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_p
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
     size_t i;                               /* Boucle de parcours #1       */
@@ -442,7 +488,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
     /* Enregistrements en masse */
 
     for (i = 0; i < node->count && result; i++)
-        result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]);
+        result = enroll_prepared_atom(&node->raw[i], backend, &node->atoms[i]);
 
  exit:
 
@@ -453,6 +499,34 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : node    = définition de la bribe à peaufiner.                *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère un identifiant final pour un atome d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_plain_build_id(GScanTokenNodePlain *node, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+    size_t i;                               /* Boucle de parcours #1       */
+
+    result = true;
+
+    for (i = 0; i < node->count && result; i++)
+        result = build_atom_pattern_id(&node->atoms[i], backend);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : raw     = contneu brut à retrouver idéalement.               *
 *                atom    = contenu brut représentatif ciblé.                  *
 *                nocase  = marque un éventuel désintérêt pour la casse.       *
@@ -478,11 +552,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
 
     init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
 
-    /* Validation du contenu avant l'atome */
+    /* Validation du motif intégral */
 
-    if (atom->pos > 0)
+    if (atom == NULL)
     {
-        ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
+        ptr = g_binary_content_get_raw_access(content, &pos, raw->len);
 
         /**
          * Si la partion atomique recherchée est trouvée en début de contenu,
@@ -492,39 +566,67 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
         if (ptr == NULL) goto done;
 
         if (nocase)
-            ret = memcasecmp(raw->data, ptr, atom->pos);
+            ret = memcasecmp(raw->data, ptr, raw->len);
         else
-            ret = memcmp(raw->data, ptr, atom->pos);
+            ret = memcmp(raw->data, ptr, raw->len);
 
-        if (ret != 0) goto done;
+        result = (ret == 0);
 
     }
 
-    /* Validation du contenu après l'atome */
+    /* Validation des extrémités */
 
-    if (atom->rem > 0)
+    else
     {
-        advance_vmpa(&pos, atom->len);
+        /* Validation du contenu avant l'atome */
 
-        ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
+        if (atom->pos > 0)
+        {
+            ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
 
-        /**
-         * Si la partion atomique recherchée est trouvée en fin de contenu,
-         * le reste du motif de recherche va déborder. L'accès correspondant
-         * est donc refusé, et cette situation est prise en compte ici.
-         */
-        if (ptr == NULL) goto done;
+            /**
+             * Si la partion atomique recherchée est trouvée en début de contenu,
+             * le reste du motif de recherche va déborder. L'accès correspondant
+             * est donc refusé, et cette situation est prise en compte ici.
+             */
+            if (ptr == NULL) goto done;
 
-        if (nocase)
-            ret = memcasecmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
-        else
-            ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+            if (nocase)
+                ret = memcasecmp(raw->data, ptr, atom->pos);
+            else
+                ret = memcmp(raw->data, ptr, atom->pos);
 
-        if (ret != 0) goto done;
+            if (ret != 0) goto done;
 
-    }
+        }
 
-    result = true;
+        /* Validation du contenu après l'atome */
+
+        if (atom->rem > 0)
+        {
+            advance_vmpa(&pos, atom->len);
+
+            ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
+
+            /**
+             * Si la partion atomique recherchée est trouvée en fin de contenu,
+             * le reste du motif de recherche va déborder. L'accès correspondant
+             * est donc refusé, et cette situation est prise en compte ici.
+             */
+            if (ptr == NULL) goto done;
+
+            if (nocase)
+                ret = memcasecmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+            else
+                ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+
+            if (ret != 0) goto done;
+
+        }
+
+        result = true;
+
+    }
 
  done:
 
@@ -535,13 +637,10 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -551,236 +650,408 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
-    bool initialized;                       /* Initialisation du suivi ?   */
     bool track_path;                        /* Conservation du chemin      */
     bool nocase;                            /* Pas d'intérêt pour la casse */
-    size_t ocount;                          /* Quantité de bornes présentes*/
     size_t i;                               /* Boucle de parcours #1       */
     const sized_binary_t *raw;              /* Données brutes d'origine    */
     const tracked_scan_atom_t *atom;        /* Atome correspondant         */
-    size_t count;                           /* Quantité de bribes trouvées */
-    const phys_t *found;                    /* Localisations des bribes    */
-    size_t k;                               /* Boucle de parcours #2       */
-    phys_t new_begin;                       /* Nouveau départ à tester     */
+    GUMemSlice *atoms;                      /* Localisations des bribes    */
+    const umem_slice_iter_t *aiter;         /* Boucle de parcours #2       */
+    match_area_t *end;                      /* Borne de fin de parcours    */
+    match_area_t *pos;                      /* Position courante           */
     bool status;                            /* Bilan d'une correspondance  */
-    size_t pcount;                          /* Nombre de correspondances   */
-    match_area_t * const *pending_ptr;      /* Correspondances actuelles   */
-    size_t p;                               /* Boucle de parcours #3       */
-    const match_area_t *pending;            /* Correspondance à traiter    */
+    match_area_t *area;                     /* Correspondance à valider    */
+    match_area_t *next;                     /* Correspondance suivante     */
+    phys_t after;                           /* Espace disposible après     */
+    phys_t min_end;                         /* Fin la plus proche possible */
+    phys_t max_end;                         /* Fin la plus éloignée trouvée*/
+    bool updated;                           /* Existence de correspondance */
+    size_t rcount;                          /* Quantité de bornes présentes*/
+    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */
+    size_t r;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t p;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t updated_edge;                    /* Nouvelle bordure de motif   */
+    match_area_t *new_area;                 /* Copie de correspondance     */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
 
     if (*skip)
         return;
 
-    initialized = are_pending_matches_initialized(matches);
-
     track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN);
 
     nocase = (node->flags & SPNF_CASE_INSENSITIVE);
 
-    get_node_search_offset_ranges(offset, &ocount);
-
-    for (i = 0; i < node->count; i++)
+    /**
+     * Création de premières marques de correspondances.
+     */
+    if (!params->initialized)
     {
-        raw = &node->raw[i];
-        atom = &node->atoms[i];
+        for (i = 0; i < node->count; i++)
+        {
+            raw = &node->raw[i];
+            atom = &node->atoms[i];
 
-        found = g_scan_context_get_atom_matches(context, atom->pid, &count);
+            atoms = g_scan_context_get_atom_matches(params->context, atom->pid);
 
-        if (!initialized)
-        {
-            for (k = 0; k < count; k++)
+            if (atom->fast_check)
             {
-                new_begin = found[k] - atom->pos;
-
-                /**
-                 * Si personne n'a manipulé les pré-résultats, mais qu'un décallage
-                 * est spécifié par un noeud précédent, une validation sur la base
-                 * d'une position 0 est menée.
-                 */
-                if (ocount > 0)
+                for (aiter = g_umem_slice_get_iter(atoms); aiter != NULL; aiter = aiter->next)
                 {
-                    if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin))
+                    end = aiter->data_end;
+
+                    for (pos = aiter->data; pos < end; pos++)
                     {
-                        if (not)
-                            add_pending_match(matches, new_begin, raw->len);
+                        /**
+                         * La modification de la zone d'origine est possible dans tous les cas
+                         * car cette zone a été allouée de façon dédiée à un type de correspondances
+                         * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+                         */
+                        pos->end = pos->start + atom->len;
 
-                        continue;
+                        if (cflags & TNCF_KEEP_DISCARDED)
+                        {
+                            add_tail_match_area(pos, &params->kept_areas);
+                            params->kept_count++;
+                        }
+
+                        else if (cflags & TNCF_CREATE_NEW)
+                        {
+                            add_tail_match_area(pos, &params->created_areas);
+                            params->created_count++;
+                        }
+
+                        else
+                        {
+                            assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+                            add_tail_match_area(pos, &params->main_areas);
+                            params->main_count++;
+
+                        }
 
                     }
+
                 }
 
-                status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
+            }
 
-                if ((status && !not) || (!status && not))
+            else
+            {
+                for (aiter = g_umem_slice_get_iter(atoms); aiter != NULL; aiter = aiter->next)
                 {
-                    /**
-                     * Il ne peut y avoir qu'une seule séquence d'octets à un même
-                     * emplacement, donc le couple (new_begin, len) enregistré est
-                     * unique.
-                     */
-                    if (track_path)
-                        add_pending_match_with_path(matches, new_begin, raw->len, i);
-                    else
-                        add_pending_match(matches, new_begin, raw->len);
+                    end = aiter->data_end;
+
+                    for (pos = aiter->data; pos < end; pos++)
+                    {
+                        status = check_scan_token_node_plain_content(raw, atom, nocase,
+                                                                     pos->start - atom->pos, params->content);
+
+                        if (status)
+                        {
+                            /**
+                             * La modification de la zone d'origine est possible dans tous les cas
+                             * car cette zone a été allouée de façon dédiée à un type de correspondances
+                             * et ne sera pas réutilisée comme autre source de correspondance ailleurs.
+                             */
+                            pos->start -= atom->pos;
+                            pos->end = pos->start + raw->len;
+
+                            if (cflags & TNCF_KEEP_DISCARDED)
+                            {
+                                add_tail_match_area(pos, &params->kept_areas);
+                                params->kept_count++;
+                            }
+
+                            else if (cflags & TNCF_CREATE_NEW)
+                            {
+                                add_tail_match_area(pos, &params->created_areas);
+                                params->created_count++;
+                            }
+
+                            else
+                            {
+                                assert(cflags & TNCF_UPDATE_IN_PLACE);
+
+                                add_tail_match_area(pos, &params->main_areas);
+                                params->main_count++;
+
+                            }
+
+                        }
+
+                    }
 
                 }
 
+
             }
 
         }
 
-        else
-        {
-            reset_pending_matches_ttl(matches);
+    }
 
-            pending_ptr = get_all_pending_matches(matches, &pcount);
+    /**
+     * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+     * des comparaisons entières de motifs.
+     */
+    else
+    {
+        if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
 
-            for (p = 0; p < pcount; p++)
+        for_each_match_area_safe(area, &params->main_areas, next)
+        {
+            assert(area->end <= params->content_end);
+
+            after = params->content_end - area->end;
+
+            if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+            /**
+             * Il ne peut y avoir qu'une seule séquence d'octets à un même
+             * emplacement. En revanche, des modificateurs peuvent construire
+             * possédant une même base, mais offrant des suffixes différents
+             * (par exemple, un marqueur nul UTF-16 final en complément).
+             *
+             * L'ensemble des combinaisons produites doit ainsi être exploré.
+             */
+
+            /**
+             * Par ailleurs, même si une base de couples uniques est assurée,
+             * la constitution d'un ensemble de noeuds peut amener une redondance
+             * dans les emplacements de correspondances ; ces doublons éventuels
+             * sont alors filtrés par un appel à sort_match_areas_no_dup().
+             *
+             * Par exemple, pour la séquence d'octets analysés suivante :
+             *
+             *    aaa....bbb
+             *
+             * La définition { (61 61 | 61 61 61) [4-5] 62 62 62 } peut établir
+             * les correspondances suivantes :
+             *
+             *    aa.....bbb -> couple pending[x] (0;2) puis (0;10)
+             *           ^
+             *     aa....bbb -> couple pending[y] (1;3) puis (1;10)
+             *           ^
+             *    aaa....bbb -> couple pending[z] (0;3) puis (0;10)
+             *           ^
+             *
+             * Par ailleurs, une même base de départ peut conduire à plusieurs
+             * zones de correspondances.
+             *
+             * Par exemple, pour la séquence d'octets analysés suivante :
+             *
+             *    aa..bb..bb
+             *
+             * La définition { 61 61 [2-6] 62 62 } peut établir
+             * les correspondances suivantes :
+             *
+             *    aa..bb..bb -> couple pending[x] (0;2) puis (0;6)
+             *        ^
+             *    aa..bb..bb -> couple pending[x] (0;2) puis (0;10)
+             *            ^
+             */
+
+            /**
+             * Dans la première situation, c'est la bribe 62 62 62 qui fait l'objet
+             * d'une recherche de motifs. Les autres bribes sont recherchées
+             * manuellement ici, car l'espace de séparation est léger (inférieur à
+             * MAX_RANGE_FOR_MANUAL_CHECK).
+             *
+             * La seconde situation bénéficie de recherches automatisées pour
+             * l'ensemble des motifs, du fait d'une valeur de séparation plus
+             * importante.
+             *
+             * Dans les deux cas, l'espace de séparation est entièrement considéré.
+             * La sélection de la correspondance à retour s'établit selon un
+             * paramètre de configuation : doit-on être avare sur les distances
+             * consommées ou non ?
+             */
+
+            min_end = params->content_end;
+            max_end = params->content_start;
+
+            updated = false;
+
+            for (i = 0; i < node->count; i++)
             {
-                pending = (*pending_ptr) + p;
+                raw = &node->raw[i];
 
-                assert(matches->content_start <= pending->start);
-
-                for (k = 0; k < count; k++)
+                /* Souplesse dans les positions ? */
+                if (offsets_exist(&params->offset))
                 {
-                    new_begin = found[k] - atom->pos;
+                    ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
 
-                    /**
-                     * Si bornes de tolérance il y a, on valide la position.
-                     *
-                     * Sinon les correspondances passées et actuelle doivent
-                     * être jointes.
-                     */
-                    if (ocount > 0)
+                    for (r = 0; r < rcount; r++)
                     {
-                        if (!does_node_search_offset_include_pos_forward(offset, pending->end, new_begin))
+                        assert(ranges[r].has_max);
+                        assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+                        for (p = ranges[r].min; p <= ranges[r].max; p++)
                         {
-                            if (not)
+                            /**
+                             * Si la fin d'une correspondance potentielle est trop près de
+                             * la fin du contenu binaire et ne peut contenir le motif
+                             * représenté, alors la corresponance est écartée sans appel.
+                             */
+                            if ((p + raw->len) > after)
+                                break;
+
+                            status = check_scan_token_node_plain_content(raw, NULL, nocase,
+                                                                         area->end + p, params->content);
+
+                            if (status)
                             {
-                                extend_pending_match_ending(matches, p, pending->end + raw->len);
+                                updated_edge = area->end + p + raw->len;
 
-                                /**
-                                 * Comme l'extension a pu conduire à un ajout et donc à une
-                                 * réallocation de la liste, on recharge l'élément pour les
-                                 * itérations suivantes.
-                                 */
-                                pending = (*pending_ptr) + p;
+                                if (updated_edge < min_end)
+                                    min_end = updated_edge;
 
-                            }
+                                if (updated_edge > max_end)
+                                    max_end = updated_edge;
 
-                            continue;
+                                updated = true;
+
+                            }
 
                         }
+
                     }
-                    else
+
+                }
+
+                /* Position immédiatement attendue */
+                else
+                {
+                    /**
+                     * Si la fin d'une correspondance potentielle est trop près de
+                     * la fin du contenu binaire et ne peut contenir le motif
+                     * représenté, alors la corresponance est écartée sans appel.
+                     */
+                    if (raw->len > after)
+                        continue;
+
+                    status = check_scan_token_node_plain_content(raw, NULL, nocase, area->end, params->content);
+
+                    if (status)
                     {
-                        if (pending->end != new_begin)
-                        {
-                            if (not)
-                            {
-                                extend_pending_match_ending(matches, p, pending->end + raw->len);
+                        updated_edge = area->end + raw->len;
 
-                                /**
-                                 * Comme l'extension a pu conduire à un ajout et donc à une
-                                 * réallocation de la liste, on recharge l'élément pour les
-                                 * itérations suivantes.
-                                 */
-                                pending = (*pending_ptr) + p;
+                        if (updated_edge < min_end)
+                            min_end = updated_edge;
 
-                            }
+                        if (updated_edge > max_end)
+                            max_end = updated_edge;
 
-                            continue;
+                        updated = true;
 
-                        }
                     }
 
-                    status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
+                }
 
-                    if ((status && !not) || (!status && not))
+            }
+
+            if (updated)
+            {
+                /**
+                 * Si seuls les rejets sont d'intérêt, les correspondances établies
+                 * ne se voient pas mises à jours ni retirées.
+                 */
+
+                if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                        area->end = (1 /* greedy */ ? min_end : max_end);
+
+                    else if (cflags & TNCF_CREATE_NEW)
                     {
-                        /**
-                         * Même si une base de couples uniques est assurée,
-                         * la constitution d'un ensemble de noeuds peut amener une
-                         * redondance dans les emplacements de correspondances.
-                         *
-                         * Par exemple, pour la séquence d'octets analysés suivante :
-                         *
-                         *    aaa....bbb
-                         *
-                         * La définition { (61 61 | 61 61 61) [4-5] 62 62 62 } peut établir
-                         * les correspondances suivantes :
-                         *
-                         *    aa.....bbb -> couple pending[x] (0;2) puis (0;10)
-                         *           ^
-                         *     aa....bbb -> couple pending[y] (1;3) puis (1;10)
-                         *           ^
-                         *    aaa....bbb -> couple pending[z] (0;3) puis (0;10)
-                         *           ^
-                         *
-                         * Par ailleurs, une même base de départ peut conduire
-                         * à plusieurs zone de correspondances.
-                         *
-                         * Par exemple, pour la séquence d'octets analysés suivante :
-                         *
-                         *    aa..bb..bb
-                         *
-                         * La définition { 61 61 [2-6] 62 62 } peut établir
-                         * les correspondances suivantes :
-                         *
-                         *    aa..bb..bb -> couple pending[x] (0;2) puis (0;6)
-                         *        ^
-                         *    aa..bb..bb -> couple pending[x] (0;2) puis (0;10)
-                         *            ^
-                         */
+                        new_area = g_umem_slice_alloc(params->allocator);
 
-                        /**
-                         * La seconde situation est prise en compte par la fonction
-                         * extend_pending_match_ending() qui s'appuie sur le TTL pour
-                         * dupliquer la correspondance pending[x] initiale. Le nouvel
-                         * élément est placé en fin de liste, ce qui ne boulverse pas
-                         * le parcours de liste courant, la valeur de pcount n'étant
-                         * pas actualisée.
-                         */
+                        *new_area = *area;
 
-                        extend_pending_match_ending(matches, p, new_begin + raw->len);
+                        new_area->end = (1 /* greedy */ ? min_end : max_end);
 
-                        /**
-                         * Comme l'extension a pu conduire à un ajout et donc à une
-                         * réallocation de la liste, on recharge l'élément pour les
-                         * itérations suivantes.
-                         */
-                        pending = (*pending_ptr) + p;
+                        add_tail_match_area(new_area, &params->created_areas);
+                        params->created_count++;
 
                     }
 
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
                 }
 
             }
 
-            purge_pending_matches(matches);
+            else
+            {
+                /**
+                 * Si la liste principale doit être mise à jour...
+                 */
+
+                if (cflags & TNCF_UPDATE_IN_PLACE)
+                {
+                    del_match_area(area, &params->main_areas);
+                    assert(params->main_count > 0);
+                    params->main_count--;
+                }
+
+                /**
+                 * Au cas où le rejet est d'intérêt, l'absence de correspondance
+                 * est conservée dans une liste dédiée.
+                 */
+
+                if (cflags & TNCF_KEEP_DISCARDED)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                    {
+                        add_tail_match_area(area, &params->kept_areas);
+                        params->kept_count++;
+                    }
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->end = (1 /* greedy */ ? min_end : max_end);
+
+                        add_tail_match_area(new_area, &params->kept_areas);
+                        params->kept_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
+                }
+
+            }
 
         }
 
     }
 
-    set_pending_matches_initialized(matches);
+    params->initialized = true;
 
-    disable_all_ranges_in_node_search_offset(offset);
+    disable_all_ranges_in_node_search_offset(&params->offset);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -790,19 +1061,272 @@ static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *nod
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_plain_check_backward(const GScanTokenNodePlain *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
 
 
 
+
+
+    bool track_path;                        /* Conservation du chemin      */
+    bool nocase;                            /* Pas d'intérêt pour la casse */
+
+
+
+
+    size_t i;                               /* Boucle de parcours #1       */
+
+
+    const sized_binary_t *raw;              /* Données brutes d'origine    */
+
+
+    bool status;                            /* Bilan d'une correspondance  */
+
+
+
+
+
+    match_area_t *area;                     /* Correspondance à valider    */
+    match_area_t *next;                     /* Correspondance suivante     */
+    phys_t before;                          /* Espace disposible avant     */
+    phys_t min_start;                       /* Début le plus proche trouvé */
+    phys_t max_start;                       /* Début le plus distant trouvé*/
+    bool updated;                           /* Existence de correspondance */
+    size_t rcount;                          /* Quantité de bornes présentes*/
+    const node_offset_range_t *ranges;      /* Bornes d'espace à parcourir */
+    size_t r;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t p;                               /* Boucle de parcours #xxxxxxxxxxxx*/
+    phys_t updated_edge;                    /* Nouvelle bordure de motif   */
+    match_area_t *new_area;                 /* Copie de correspondance     */
+
+    if (0x1) printf("=================== CHECK :: %s (skip? %d)\n", __FUNCTION__, *skip);
+
     if (*skip)
         return;
 
+    /**
+     * En lecture à rebourd, au moins un noeud a été solicité pour analyse (lors
+     * du sens de lecture normal). Donc l'initialisation a déjà dû avoir lieu.
+     */
+
+    assert(params->initialized);
+
+    track_path = (G_SCAN_TOKEN_NODE(node)->flags & STNF_MAIN);
+
+    nocase = (node->flags & SPNF_CASE_INSENSITIVE);
+
 
 
-    printf("TODO\n");
-    assert(0);
+    /**
+     * .............
+     */
+    if (0)
+    {
+
+
+        ;
+
+
+
+    }
+
+    /**
+     * Poursuite des traitements sur des correspondances déjà amorcées, impliquant
+     * des comparaisons entières de motifs.
+     */
+    else
+    {
+        if (0x1) printf(" LIST : %p (sz = %zu)\n", params->main_areas, params->main_count);
+
+        for_each_match_area_safe(area, &params->main_areas, next)
+        {
+            assert(params->content_start <= area->start);
+
+            before = area->start - params->content_start;
+
+            if (0x1) printf("---------- iter @ %u -> %u\n", (unsigned int)area->start, (unsigned int)area->end);
+
+            /**
+             * Il ne peut y avoir qu'une seule séquence d'octets à un même
+             * emplacement. En revanche, des modificateurs peuvent construire
+             * possédant une même base, mais offrant des suffixes différents
+             * (par exemple, un marqueur nul UTF-16 final en complément).
+             *
+             * L'ensemble des combinaisons produites doit ainsi être exploré.
+             */
+
+            min_start = params->content_start;
+            max_start = params->content_end;
+
+            updated = false;
+
+            for (i = 0; i < node->count; i++)
+            {
+                raw = &node->raw[i];
+
+                /* Souplesse dans les positions ? */
+                if (offsets_exist(&params->offset))
+                {
+                    ranges = get_node_search_offset_ranges_2(&params->offset, &rcount);
 
+                    for (r = 0; r < rcount; r++)
+                    {
+                        assert(ranges[r].has_max);
+                        assert((ranges[r].max - ranges[r].min) <= MAX_RANGE_FOR_MANUAL_CHECK);
+
+                        for (p = ranges[r].min; p <= ranges[r].max; p++)
+                        {
+                            /**
+                             * Si la fin d'une correspondance potentielle est trop près de
+                             * la fin du contenu binaire et ne peut contenir le motif
+                             * représenté, alors la corresponance est écartée sans appel.
+                             */
+                            if ((p + raw->len) > before)
+                                break;
+
+                            status = check_scan_token_node_plain_content(raw, NULL, nocase,
+                                                                         area->start - raw->len - p,
+                                                                         params->content);
+
+                            if (status)
+                            {
+                                updated_edge = area->start - raw->len - p;
+
+                                if (updated_edge > min_start)
+                                    min_start = updated_edge;
+
+                                if (updated_edge < max_start)
+                                    max_start = updated_edge;
+
+                                updated = true;
+
+                            }
+
+                        }
+
+                    }
+
+                }
+
+                /* Position immédiatement attendue */
+                else
+                {
+                    /**
+                     * Si la fin d'une correspondance potentielle est trop près du
+                     * début du contenu binaire et ne peut contenir le motif
+                     * représenté, alors la corresponance est écartée sans appel.
+                     */
+                    if (raw->len > before)
+                        continue;
+
+                    status = check_scan_token_node_plain_content(raw, NULL, nocase,
+                                                                 area->start - raw->len,
+                                                                 params->content);
+
+                    if (status)
+                    {
+                        updated_edge = area->start - raw->len;
+
+                        if (updated_edge > min_start)
+                            min_start = updated_edge;
+
+                        if (updated_edge < max_start)
+                            max_start = updated_edge;
+
+                        updated = true;
+
+                    }
+
+                }
+
+            }
+
+            if (updated)
+            {
+                /**
+                 * Si seuls les rejets sont d'intérêt, les correspondances établies
+                 * ne se voient pas mises à jours ni retirées.
+                 */
+
+                if ((cflags & TNCF_KEEP_DISCARDED) == 0)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                        area->start = (1 /* greedy */ ? min_start : max_start);
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+                        add_tail_match_area(new_area, &params->created_areas);
+                        params->created_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
+                }
+
+            }
+
+            else
+            {
+                /**
+                 * Si la liste principale doit être mise à jour...
+                 */
+
+                if (cflags & TNCF_UPDATE_IN_PLACE)
+                {
+                    del_match_area(area, &params->main_areas);
+                    assert(params->main_count > 0);
+                    params->main_count--;
+                }
+
+                /**
+                 * Au cas où le rejet est d'intérêt, l'absence de correspondance
+                 * est conservée dans une liste dédiée.
+                 */
+
+                if (cflags & TNCF_KEEP_DISCARDED)
+                {
+                    if (cflags & TNCF_UPDATE_IN_PLACE)
+                    {
+                        add_tail_match_area(area, &params->kept_areas);
+                        params->kept_count++;
+                    }
+
+                    else if (cflags & TNCF_CREATE_NEW)
+                    {
+                        new_area = g_umem_slice_alloc(params->allocator);
+
+                        *new_area = *area;
+
+                        new_area->start = (1 /* greedy */ ? min_start : max_start);
+
+                        add_tail_match_area(new_area, &params->kept_areas);
+                        params->kept_count++;
+
+                    }
+
+#ifndef NDEBUG
+                    else
+                        assert(false);
+#endif
+
+                }
+
+            }
+
+        }
+
+    }
 
+    disable_all_ranges_in_node_search_offset(&params->offset);
 
 }
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.c b/src/analysis/scan/patterns/tokens/nodes/sequence.c
index 91307bf..394c877 100644
--- a/src/analysis/scan/patterns/tokens/nodes/sequence.c
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.c
@@ -24,6 +24,9 @@
 #include "sequence.h"
 
 
+#include <assert.h>
+
+
 #include "any.h"
 #include "sequence-int.h"
 
@@ -49,17 +52,23 @@ static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *);
 /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
 
 
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+static void g_scan_token_node_sequence_apply_flags(GScanTokenNodeSequence *, ScanTokenNodeFlags);
+
 /* Parcourt une arborescence de noeuds et y relève des éléments. */
 static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *);
 
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *, GScanContext *, GEngineBackend *, size_t, size_t *);
+static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *, GEngineBackend *, size_t, size_t *);
+
+/* Récupère un identifiant final pour un atome d'octets. */
+static bool g_scan_token_node_sequence_build_id(GScanTokenNodeSequence *, GEngineBackend *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 /* Transforme les correspondances locales en trouvailles. */
-static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
+static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *, scan_node_check_params_t *, TokenNodeCheckFlags, bool *);
 
 
 
@@ -76,7 +85,7 @@ G_DEFINE_TYPE(GScanTokenNodeSequence, g_scan_token_node_sequence, G_TYPE_SCAN_TO
 *                                                                             *
 *  Paramètres  : klass = classe à initialiser.                                *
 *                                                                             *
-*  Description : Initialise la classe des décompositions séquentielles.        *
+*  Description : Initialise la classe des décompositions séquentielles.       *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -96,8 +105,10 @@ static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *k
 
     node = G_SCAN_TOKEN_NODE_CLASS(klass);
 
+    node->apply = (apply_scan_token_node_flags_fc)g_scan_token_node_sequence_apply_flags;
     node->visit = (visit_scan_token_node_fc)g_scan_token_node_sequence_visit;
     node->enroll = (enroll_scan_token_node_fc)g_scan_token_node_sequence_enroll;
+    node->build_id = (build_scan_token_node_id_fc)g_scan_token_node_sequence_build_id;
     node->check_forward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_forward;
     node->check_backward = (check_scan_token_node_fc)g_scan_token_node_sequence_check_backward;
 
@@ -330,6 +341,40 @@ GScanTokenNode *g_scan_token_node_sequence_get(const GScanTokenNodeSequence *seq
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : node  = noeud de motif à mettre à jour.                      *
+*                flags = propriétés particulières à associer au noeud.        *
+*                                                                             *
+*  Description : Prend acte d'une nouvelle propriété pour le noeud.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_apply_flags(GScanTokenNodeSequence *node, ScanTokenNodeFlags flags)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    if (node->count == 1)
+        g_scan_token_node_set_flags(node->children[0], flags);
+
+    else if (node->count > 1)
+    {
+        g_scan_token_node_set_flags(node->children[0], flags & ~STNF_LAST);
+
+        for (i = 1; i < (node->count - 1); i++)
+            g_scan_token_node_set_flags(node->children[i], flags & ~(STNF_FIRST | STNF_LAST));
+
+        g_scan_token_node_set_flags(node->children[node->count - 1], flags & ~STNF_FIRST);
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : node   = point de départ du parcours à effectuer.            *
 *                points = points capitaux de l'arborescence. [OUT]            *
 *                                                                             *
@@ -354,7 +399,6 @@ static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : node    = définition de la bribe à enregistrer.              *
-*                context = contexte de l'analyse à mener.                     *
 *                backend = moteur de recherche à préchauffer.                 *
 *                maxsize = taille max. des atomes (mise en commun optimisée). *
 *                slow    = niveau de ralentissement induit (0 = idéal). [OUT] *
@@ -367,7 +411,7 @@ static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
     size_t i;                               /* Boucle de parcours          */
@@ -375,7 +419,35 @@ static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GSca
     result = true;
 
     for (i = 0; i < node->count && result; i++)
-        result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow);
+        result = _g_scan_token_node_enroll(node->children[i], backend, maxsize, slow);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node    = définition de la bribe à peaufiner.                *
+*                backend = moteur de recherche à préchauffer.                 *
+*                                                                             *
+*  Description : Récupère un identifiant final pour un atome d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_sequence_build_id(GScanTokenNodeSequence *node, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+    size_t i;                               /* Boucle de parcours #1       */
+
+    result = true;
+
+    for (i = 0; i < node->count && result; i++)
+        result = g_scan_token_node_build_id(node->children[i], backend);
 
     return result;
 
@@ -384,13 +456,10 @@ static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GSca
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -400,25 +469,22 @@ static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GSca
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
     size_t i;                               /* Boucle de parcours          */
 
     for (i = 0; i < node->count; i++)
-        _g_scan_token_node_check_forward(node->children[i], context, content, matches, offset, not, skip);
+        _g_scan_token_node_check_forward(node->children[i], params, cflags, skip);
 
 }
 
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : node    = définition de la bribe à manipuler.                *
-*                context = contexte de l'analyse à mener.                     *
-*                content = accès au contenu brut pour vérifications (optim.)  *
-*                matches = suivi des correspondances à consolider.            *
-*                offset  = tolérance dans les positions à appliquer.          *
-*                not     = indique si les résultats doivent être inversés.    *
-*                skip    = détermine si l'analyse est différée. [OUT]         *
+*  Paramètres  : node   = définition de la bribe à manipuler.                 *
+*                params = accès direct aux éléments utiles aux validations.   *
+*                cflags = altérations de traitement à respecter.              *
+*                skip   = détermine si l'analyse est différée. [OUT]          *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -428,11 +494,11 @@ static void g_scan_token_node_sequence_check_forward(const GScanTokenNodeSequenc
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, node_search_offset_t *offset, bool not, bool *skip)
+static void g_scan_token_node_sequence_check_backward(const GScanTokenNodeSequence *node, scan_node_check_params_t *params, TokenNodeCheckFlags cflags, bool *skip)
 {
     size_t i;                               /* Boucle de parcours          */
 
     for (i = node->count; i > 0 ; i--)
-        _g_scan_token_node_check_backward(node->children[i - 1], context, content, matches, offset, not, skip);
+        _g_scan_token_node_check_backward(node->children[i - 1], params, cflags, skip);
 
 }
diff --git a/src/analysis/scan/patterns/tokens/offset.c b/src/analysis/scan/patterns/tokens/offset.c
index 010ec67..0a4fd91 100644
--- a/src/analysis/scan/patterns/tokens/offset.c
+++ b/src/analysis/scan/patterns/tokens/offset.c
@@ -229,6 +229,32 @@ node_offset_range_t * const *get_node_search_offset_ranges(const node_search_off
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : offset = suivi de tolérances bornées à consulter.            *
+*                count  = nombre de bornes enregistrées. [OUT]                *
+*                                                                             *
+*  Description : Fournit la liste des tolérances bornées établies à présent.  *
+*                                                                             *
+*  Retour      : Liste d'intervales en lecture seule.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+const node_offset_range_t * const get_node_search_offset_ranges_2(const node_search_offset_t *offset, size_t *count)
+{
+    node_offset_range_t *result;            /* Série à renvoyer            */
+
+    result = offset->gen_ptr;
+
+    *count = offset->used;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : offset   = suivi de tolérances bornées à consulter.          *
 *                min      = point de départ pour parcourir une zone.          *
 *                max      = point d'arrivée pour parcourir une zone.          *
@@ -318,6 +344,66 @@ void add_range_to_node_search_offset(node_search_offset_t *offset, phys_t min, p
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : offset  = suivi de tolérances bornées à consulter.           *
+*                min     = point de départ pour parcourir une zone.           *
+*                max     = point d'arrivée pour parcourir une zone.           *
+*                has_max = validité de la valeur maximale transmise.          *
+*                                                                             *
+*  Description : Etend les décalages tolérés avec un nouvel espace.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void extend_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, bool has_max)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    switch (offset->used)
+    {
+        /* Si le réceptacle unique peut être employé... */
+        case 0:
+
+            offset->range.min = min;
+            offset->range.max = max;
+            offset->range.has_max = has_max;
+
+            offset->used = 1;
+
+            offset->gen_ptr = &offset->range;
+
+            break;
+
+        /* Si un espace unique est enregistré */
+        case 1:
+
+            offset->range.min += min;
+            offset->range.max += max;
+            offset->range.has_max &= has_max;
+
+            break;
+
+        /* Sinon le groupe dynamique est sollicité */
+        default:
+
+            for (i = 0; i < offset->used; i++)
+            {
+                offset->ranges[i].min += min;
+                offset->ranges[i].max += max;
+                offset->ranges[i].has_max &= has_max;
+            }
+
+            break;
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  Paramètres  : offset = suivi de tolérances bornées à consulter.            *
 *                last   = dernière position validée.                          *
 *                pos    = nouvelle position potentielle.                      *
diff --git a/src/analysis/scan/patterns/tokens/offset.h b/src/analysis/scan/patterns/tokens/offset.h
index b458717..130aaea 100644
--- a/src/analysis/scan/patterns/tokens/offset.h
+++ b/src/analysis/scan/patterns/tokens/offset.h
@@ -36,7 +36,7 @@ typedef struct _node_offset_range_t
 {
     /**
      * Les deux champs ci-après font bien référence à des positions absolues,
-     * et non à des bornes d'espace, lors que les résultats de correspondances
+     * et non à des bornes d'espace, lorsque les résultats de correspondances
      * sont encore non initialisés.
      *
      * Ensuite ces bornes représentent bien un espace séparant les résultats
@@ -44,6 +44,7 @@ typedef struct _node_offset_range_t
      */
     phys_t min;                             /* Position minimale           */
     phys_t max;                             /* Position maximale           */
+    bool has_max;                           /* Quantité définie ?          */
 
 } node_offset_range_t;
 
@@ -53,6 +54,7 @@ bool get_node_offset_range(const node_offset_range_t *, phys_t, phys_t, phys_t *
 
 
 
+#define MAX_RANGE_FOR_MANUAL_CHECK 5
 
 
 
@@ -83,13 +85,21 @@ void merge_node_search_offset(node_search_offset_t *, const node_search_offset_t
 /* Met fin à une mémorisation d'intervales de tolérance. */
 void exit_node_search_offset(node_search_offset_t *);
 
+#define offsets_exist(off) \
+    ((off)->used > 0)
+
+
 /* Fournit la liste des tolérances bornées établies à présent. */
 /* TODO : supprimer un niveau d'indirection */
 node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *, size_t *);
+const node_offset_range_t * const get_node_search_offset_ranges_2(const node_search_offset_t *, size_t *);
 
 /* Ajoute un nouvel espace borné aux décalages tolérés. */
 void add_range_to_node_search_offset(node_search_offset_t *, phys_t, phys_t, const phys_t *);
 
+/* Etend les décalages tolérés avec un nouvel espace. */
+void extend_node_search_offset(node_search_offset_t *, phys_t, phys_t, bool);
+
 #define disable_all_ranges_in_node_search_offset(off) \
     (off)->used = 0
 
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
index 638dae5..14a6d38 100644
--- a/src/analysis/scan/rule.c
+++ b/src/analysis/scan/rule.c
@@ -541,7 +541,6 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo
     bool result;                            /* Statut à retourner          */
     size_t maxsize;                         /* Taille maximale des atomes  */
     GSearchPattern *pattern;                /* Motif à intégrer            */
-    GScanOptions *options;                  /* Options d'analyse           */
     size_t i;                               /* Boucle de parcours          */
 
     /* Suivi des conditions de correspondance */
@@ -556,22 +555,42 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo
     for (i = 0; i < rule->bytes_used && result; i++)
     {
         pattern = rule->bytes_locals[i];
-        result = g_bytes_token_enroll(G_BYTES_TOKEN(pattern), context, backend, maxsize);
+        result = g_bytes_token_enroll(G_BYTES_TOKEN(pattern), backend, maxsize);
     }
 
-    g_engine_backend_warm_up(backend);
+ exit:
 
-    /* Affichage éventuel de statistiques */
+    return result;
 
-    options = g_scan_context_get_options(context);
+}
 
-    if (g_scan_options_get_print_stats(options))
-        g_engine_backend_output_stats(backend);
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : rule    = règle de détection à considérer.                   *
+*                backend = moteur d'analyse pour données brutes.              *
+*                                                                             *
+*  Description : Récupère les identifiants finaux pour les motifs recherchés. *
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
 
-    g_object_unref(G_OBJECT(options));
+bool g_scan_rule_define_pattern_ids(GScanRule *rule, GEngineBackend *backend)
+{
+    bool result;                            /* Statut à retourner          */
+    size_t i;                               /* Boucle de parcours          */
+    GSearchPattern *pattern;                /* Motif à intégrer            */
 
- exit:
+    result = true;
+
+    for (i = 0; i < rule->bytes_used && result; i++)
+    {
+        pattern = rule->bytes_locals[i];
+        result = g_bytes_token_build_id(G_BYTES_TOKEN(pattern), backend);
+    }
 
     return result;
 
@@ -594,55 +613,24 @@ bool g_scan_rule_setup_backend(GScanRule *rule, GEngineBackend *backend, GScanCo
 
 void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *context)
 {
-    GBinContent *content;                   /* Contenu à manipuler         */
-    vmpa2t start;                           /* Point de début du contenu   */
-    vmpa2t end;                             /* Point de fin du contenu     */
-    pending_matches_t matches;              /* Suivi de correspondances    */
-    size_t i;                               /* Boucle de parcours #1       */
+    size_t i;                               /* Boucle de parcours          */
     GSearchPattern *pattern;                /* Motif à intégrer            */
-    size_t k;                               /* Boucle de parcours #2       */
-    match_area_t *area;                     /* Zone à initialiser          */
-    GScanMatch *match;                      /* Correspondance à mémoriser  */
-
-    content = g_scan_context_get_content(context);
-
-    g_binary_content_compute_start_pos(content, &start);
-    g_binary_content_compute_end_pos(content, &end);
-
-    /* Consolidation des résultats */
+    GScanBytesMatches *matches;             /* Correspondances établies    */
 
     for (i = 0; i < rule->bytes_used; i++)
     {
-        init_pending_matches(&matches, &start.physical, &end.physical);
-
         pattern = rule->bytes_locals[i];
 
-        g_bytes_token_check(G_BYTES_TOKEN(pattern), context, content, &matches);
-
-        g_scan_context_prepare_full_match_registration(context, pattern, matches.used);
-
-        for (k = 0; k < matches.used; k++)
-        {
-            area = &matches.areas[k];
-
-            match = g_scan_bytes_match_new(pattern, content, area->start, area->end - area->start);
+        matches = g_scan_bytes_matches_new(pattern, context);
 
-            if (area->has_mod_path)
-                g_scan_bytes_match_remember_modifier_path(G_SCAN_BYTES_MATCH(match), area->mod_path_index);
+        g_bytes_token_check(G_BYTES_TOKEN(pattern), matches);
 
-            g_scan_context_register_full_match(context, match);
-            g_object_unref(G_OBJECT(match));
+        g_scan_context_register_full_matches(context, pattern, matches);
 
-        }
-
-        exit_pending_matches(&matches);
+        g_object_unref(G_OBJECT(matches));
 
     }
 
-    /* Sortie propre */
-
-    g_object_unref(G_OBJECT(content));
-
 }
 
 
diff --git a/src/analysis/scan/rule.h b/src/analysis/scan/rule.h
index b73ee1a..ea38655 100644
--- a/src/analysis/scan/rule.h
+++ b/src/analysis/scan/rule.h
@@ -96,6 +96,9 @@ void g_scan_rule_set_match_condition(GScanRule *, GScanExpression *);
 /* Prépare le suivi de recherche de motifs pour une règle. */
 bool g_scan_rule_setup_backend(GScanRule *, GEngineBackend *, GScanContext *);
 
+/* Récupère les identifiants finaux pour les motifs recherchés. */
+bool g_scan_rule_define_pattern_ids(GScanRule *, GEngineBackend *);
+
 /* Lance une analyse d'un contenu binaire selon une règle. */
 void g_scan_rule_check(GScanRule *, GEngineBackend *, GScanContext *);
 
diff --git a/src/analysis/scan/scanner.c b/src/analysis/scan/scanner.c
index 1f90393..507fa6f 100644
--- a/src/analysis/scan/scanner.c
+++ b/src/analysis/scan/scanner.c
@@ -482,17 +482,50 @@ bool g_content_scanner_add_rule(GContentScanner *scanner, GScanRule *rule)
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
-
+#include <sched.h>
 GScanContext *g_content_scanner_analyze(GContentScanner *scanner, GScanOptions *options, GBinContent *content)
 {
     GScanContext *result;                   /* Bilan global à retourner    */
     bool status;                            /* Bilan d'opération locale    */
     size_t i;                               /* Boucle de parcours          */
+    size_t ids_count;                       /* Quantité de motifs prévus   */
     bool global;                            /* Bilan des règles globales   */
     GScanRule *rule;                        /* Règle à consulter           */
     const char *name;                       /* Désignation de la règle     */
 
-    /* Préparations... */
+#if 0
+
+    int policy;
+    struct sched_param sp;
+
+
+  policy = sched_getscheduler(0);
+  /*
+  switch(policy) {
+    case SCHED_OTHER: printf("SCHED_OTHER\n"); break;
+    case SCHED_RR:   printf("SCHED_RR\n"); break;
+    case SCHED_FIFO:  printf("SCHED_FIFO\n"); break;
+    default:   printf("Unknown...\n");
+  }
+
+   int policy;
+   ...
+   if((policy = sched_getscheduler(0) == -1)) {
+      fprintf(stderr, ...
+   }
+  */
+
+
+   if(policy == SCHED_OTHER) {
+      sp.sched_priority = sched_get_priority_max(SCHED_FIFO);
+      sched_setscheduler(0, SCHED_FIFO, &sp);
+   }
+
+#endif
+
+
+
+   /* Préparations... */
 
     result = g_scan_context_new(options);
 
@@ -512,11 +545,23 @@ GScanContext *g_content_scanner_analyze(GContentScanner *scanner, GScanOptions *
             goto exit;
         }
 
+        g_engine_backend_warm_up(scanner->data_backend);
+
+        for (i = 0; i < scanner->rule_count && status; i++)
+            status = g_scan_rule_define_pattern_ids(scanner->rules[i], scanner->data_backend);
+
+        /* Affichage éventuel de statistiques */
+
+        if (g_scan_options_get_print_stats(options))
+            g_engine_backend_output_stats(scanner->data_backend);
+
     }
 
     /* Phase d'analyse */
 
-    g_scan_context_set_content(result, content);
+    ids_count = g_engine_backend_count_plain_pattern_ids(scanner->data_backend);
+
+    g_scan_context_set_content(result, content, ids_count);
 
     g_engine_backend_run_scan(scanner->data_backend, result);
 
diff --git a/tests/analysis/scan/scanning_hex.py b/tests/analysis/scan/scanning_hex.py
index 442057b..4b0fda4 100644
--- a/tests/analysis/scan/scanning_hex.py
+++ b/tests/analysis/scan/scanning_hex.py
@@ -111,7 +111,7 @@ rule test {
         self.check_rule_success(rule, content=cnt)
 
 
-    def testLonelyPatternsNot(self):
+    def ___testLonelyPatternsNot(self):
         """Evaluate the most simple patterns (not version)."""
 
         cnt = MemoryContent(b'Abcdef')
@@ -696,6 +696,9 @@ rule test {
         self.check_rule_success(rule, content=cnt)
 
 
+    def testDuplicatedResultsFiltering(self):
+        """Filter duplicated results."""
+
         cnt = MemoryContent(b'123-Abc-456')
 
         rule = '''
-- 
cgit v0.11.2-87-g4458