From fed4c10b9bb1c6f99440dba3839a1e7b56b40359 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Tue, 12 Sep 2023 06:43:02 +0200
Subject: Save current state with some ROST extra features.

---
 configure.ac                                       |   2 +
 src/analysis/scan/context.c                        |   6 +-
 src/analysis/scan/core.c                           |  34 +
 src/analysis/scan/exprs/call.c                     |   2 +-
 src/analysis/scan/grammar.y                        | 288 ++++++--
 src/analysis/scan/items/Makefile.am                |   4 +-
 src/analysis/scan/items/console/log.c              |  17 +-
 src/analysis/scan/items/math/Makefile.am           |  13 +
 src/analysis/scan/items/math/to_string.c           | 381 ++++++++++
 src/analysis/scan/items/math/to_string.h           |  58 ++
 src/analysis/scan/items/string/Makefile.am         |  15 +
 src/analysis/scan/items/string/lower.c             | 270 +++++++
 src/analysis/scan/items/string/lower.h             |  58 ++
 src/analysis/scan/items/string/to_int.c            | 303 ++++++++
 src/analysis/scan/items/string/to_int.h            |  58 ++
 src/analysis/scan/items/string/upper.c             | 270 +++++++
 src/analysis/scan/items/string/upper.h             |  58 ++
 src/analysis/scan/matches/pending.c                | 279 +++++--
 src/analysis/scan/matches/pending.h                |  36 +-
 src/analysis/scan/patterns/token-int.h             |  17 +-
 src/analysis/scan/patterns/token.c                 | 140 +++-
 src/analysis/scan/patterns/token.h                 |   6 +
 src/analysis/scan/patterns/tokens/Makefile.am      |   1 +
 src/analysis/scan/patterns/tokens/atom.c           |  63 +-
 src/analysis/scan/patterns/tokens/atom.h           |   5 +-
 src/analysis/scan/patterns/tokens/hex-int.h        |   2 +-
 src/analysis/scan/patterns/tokens/hex.c            | 210 +-----
 src/analysis/scan/patterns/tokens/hex.h            |   2 +-
 src/analysis/scan/patterns/tokens/node-int.h       |  47 +-
 src/analysis/scan/patterns/tokens/node.c           | 407 ++++++++++-
 src/analysis/scan/patterns/tokens/node.h           |  34 +-
 .../scan/patterns/tokens/nodes/Makefile.am         |  14 +-
 src/analysis/scan/patterns/tokens/nodes/any-int.h  |  60 ++
 src/analysis/scan/patterns/tokens/nodes/any.c      | 425 +++++++++++
 src/analysis/scan/patterns/tokens/nodes/any.h      |  58 ++
 .../scan/patterns/tokens/nodes/choice-int.h        |  54 ++
 src/analysis/scan/patterns/tokens/nodes/choice.c   | 486 ++++++++++++
 src/analysis/scan/patterns/tokens/nodes/choice.h   |  61 ++
 src/analysis/scan/patterns/tokens/nodes/hub-int.h  |  51 --
 src/analysis/scan/patterns/tokens/nodes/hub.c      | 150 ----
 src/analysis/scan/patterns/tokens/nodes/hub.h      |  55 --
 .../scan/patterns/tokens/nodes/masked-int.h        |  63 ++
 src/analysis/scan/patterns/tokens/nodes/masked.c   | 814 +++++++++++++++++++++
 src/analysis/scan/patterns/tokens/nodes/masked.h   |  72 ++
 src/analysis/scan/patterns/tokens/nodes/not-int.h  |  57 ++
 src/analysis/scan/patterns/tokens/nodes/not.c      | 364 +++++++++
 src/analysis/scan/patterns/tokens/nodes/not.h      |  59 ++
 .../scan/patterns/tokens/nodes/plain-int.h         |   4 +-
 src/analysis/scan/patterns/tokens/nodes/plain.c    | 244 +++++-
 src/analysis/scan/patterns/tokens/nodes/plain.h    |  16 +-
 .../scan/patterns/tokens/nodes/sequence-int.h      |  58 ++
 src/analysis/scan/patterns/tokens/nodes/sequence.c | 360 +++++++++
 src/analysis/scan/patterns/tokens/nodes/sequence.h |  61 ++
 src/analysis/scan/patterns/tokens/offset.c         | 352 +++++++++
 src/analysis/scan/patterns/tokens/offset.h         | 101 +++
 src/analysis/scan/patterns/tokens/plain-int.h      |  10 +-
 src/analysis/scan/patterns/tokens/plain.c          | 257 +------
 src/analysis/scan/patterns/tokens/plain.h          |  15 +-
 src/analysis/scan/rule.c                           |   7 +-
 src/analysis/scan/tokens.l                         | 334 ++++++++-
 src/common/szstr.h                                 |   6 +-
 tests/analysis/scan/functions.py                   |  58 ++
 tests/analysis/scan/pyapi.py                       |   1 -
 tests/analysis/scan/scanning_hex.py                | 691 ++++++++++++++++-
 tests/analysis/scan/scanning_str.py                | 194 +++++
 65 files changed, 7680 insertions(+), 1018 deletions(-)
 create mode 100644 src/analysis/scan/items/math/Makefile.am
 create mode 100644 src/analysis/scan/items/math/to_string.c
 create mode 100644 src/analysis/scan/items/math/to_string.h
 create mode 100644 src/analysis/scan/items/string/Makefile.am
 create mode 100644 src/analysis/scan/items/string/lower.c
 create mode 100644 src/analysis/scan/items/string/lower.h
 create mode 100644 src/analysis/scan/items/string/to_int.c
 create mode 100644 src/analysis/scan/items/string/to_int.h
 create mode 100644 src/analysis/scan/items/string/upper.c
 create mode 100644 src/analysis/scan/items/string/upper.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/any-int.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/any.c
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/any.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/choice-int.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/choice.c
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/choice.h
 delete mode 100644 src/analysis/scan/patterns/tokens/nodes/hub-int.h
 delete mode 100644 src/analysis/scan/patterns/tokens/nodes/hub.c
 delete mode 100644 src/analysis/scan/patterns/tokens/nodes/hub.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/masked-int.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/masked.c
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/masked.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/not-int.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/not.c
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/not.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/sequence-int.h
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/sequence.c
 create mode 100644 src/analysis/scan/patterns/tokens/nodes/sequence.h
 create mode 100644 src/analysis/scan/patterns/tokens/offset.c
 create mode 100644 src/analysis/scan/patterns/tokens/offset.h
 create mode 100644 tests/analysis/scan/scanning_str.py

diff --git a/configure.ac b/configure.ac
index f9680cb..f2b6c92 100644
--- a/configure.ac
+++ b/configure.ac
@@ -731,6 +731,8 @@ AC_CONFIG_FILES([Makefile
                  src/analysis/scan/items/Makefile
                  src/analysis/scan/items/console/Makefile
                  src/analysis/scan/items/magic/Makefile
+                 src/analysis/scan/items/math/Makefile
+                 src/analysis/scan/items/string/Makefile
                  src/analysis/scan/items/time/Makefile
                  src/analysis/scan/matches/Makefile
                  src/analysis/scan/patterns/Makefile
diff --git a/src/analysis/scan/context.c b/src/analysis/scan/context.c
index 51fdd6b..9dd41cf 100644
--- a/src/analysis/scan/context.c
+++ b/src/analysis/scan/context.c
@@ -529,6 +529,8 @@ void g_scan_context_register_atom_match(GScanContext *context, patid_t id, phys_
         tracker->matches = realloc(tracker->matches, tracker->allocated * sizeof(phys_t));
     }
 
+    printf("++ register pat=%llu @ %llu\n", (unsigned long long)id, (unsigned long long)offset); // REMME
+
     tracker->matches[tracker->used++] = offset;
 
 }
@@ -585,6 +587,8 @@ void g_scan_context_register_full_match(GScanContext *context, GScanMatch *match
 
     pattern = g_scan_match_get_source(match);
 
+    printf("// register match=%p for pattern=%p\n", pattern, match); // REMME
+
     key.pattern = pattern;
 
     found = bsearch((full_match_tracker_t *[]) { &key }, context->full_trackers, context->full_count,
@@ -637,7 +641,7 @@ const GScanMatch **g_scan_context_get_full_matches(const GScanContext *context,
     if (found == NULL)
     {
         result = NULL;
-        count = 0;
+        *count = 0;
     }
 
     else
diff --git a/src/analysis/scan/core.c b/src/analysis/scan/core.c
index 3d4e529..0b2c1d5 100644
--- a/src/analysis/scan/core.c
+++ b/src/analysis/scan/core.c
@@ -37,6 +37,10 @@
 #   include "items/magic/mime-encoding.h"
 #   include "items/magic/mime-type.h"
 #endif
+#include "items/math/to_string.h"
+#include "items/string/lower.h"
+#include "items/string/to_int.h"
+#include "items/string/upper.h"
 #include "items/time/make.h"
 #include "items/time/now.h"
 #include "patterns/modifiers/hex.h"
@@ -280,6 +284,36 @@ bool populate_main_scan_namespace(GScanNamespace *space)
     }
 #endif
 
+    /* Math */
+
+    if (result)
+    {
+        ns = g_scan_namespace_new("math");
+        result = g_scan_namespace_register_item(space, G_REGISTERED_ITEM(ns));
+
+        if (result) result = REGISTER_FUNC(ns, g_scan_math_to_string_function_new());
+
+        g_object_unref(G_OBJECT(ns));
+
+    }
+
+    /* String */
+
+    if (result)
+    {
+        ns = g_scan_namespace_new("string");
+        result = g_scan_namespace_register_item(space, G_REGISTERED_ITEM(ns));
+
+        printf("g_scan_string_to_int_function_new(): %p\n", g_scan_string_to_int_function_new());
+
+        if (result) result = REGISTER_FUNC(ns, g_scan_string_lower_function_new());
+        if (result) result = REGISTER_FUNC(ns, g_scan_string_to_int_function_new());
+        if (result) result = REGISTER_FUNC(ns, g_scan_string_upper_function_new());
+
+        g_object_unref(G_OBJECT(ns));
+
+    }
+
     /* Time */
 
     if (result)
diff --git a/src/analysis/scan/exprs/call.c b/src/analysis/scan/exprs/call.c
index d9b2c13..f68159f 100644
--- a/src/analysis/scan/exprs/call.c
+++ b/src/analysis/scan/exprs/call.c
@@ -312,7 +312,7 @@ static ScanReductionState g_scan_pending_call_reduce(const GScanPendingCall *exp
 
                     for (k = 0; k < i; k++)
                     {
-                        new_args[k] = expr->args[i];
+                        new_args[k] = expr->args[k];
                         g_object_ref(G_OBJECT(new_args[k]));
                     }
 
diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y
index c0aa52d..64bcd5b 100644
--- a/src/analysis/scan/grammar.y
+++ b/src/analysis/scan/grammar.y
@@ -16,6 +16,8 @@ static int yyerror(GContentScanner *, yyscan_t, GScanRule **, sized_string_t *,
 #define YY_TYPEDEF_YY_SCANNER_T
 typedef void *yyscan_t;
 
+#include <assert.h>
+
 #include "core.h"
 #include "scanner.h"
 #include "exprs/access.h"
@@ -34,7 +36,12 @@ typedef void *yyscan_t;
 #include "patterns/modifiers/list.h"
 #include "patterns/tokens/hex.h"
 #include "patterns/tokens/plain.h"
+#include "patterns/tokens/nodes/any.h"
+#include "patterns/tokens/nodes/choice.h"
+#include "patterns/tokens/nodes/masked.h"
+#include "patterns/tokens/nodes/not.h"
 #include "patterns/tokens/nodes/plain.h"
+#include "patterns/tokens/nodes/sequence.h"
 #include "../../core/logs.h"
 
 }
@@ -52,11 +59,11 @@ typedef void *yyscan_t;
 
     sized_string_t *tmp_cstring;            /* Série d'octets reconstituée */
 
-    struct {
-        bin_t byte;                         /* Valeur partielle recherchée */
-        uint8_t mask;                       /* Masque associé              */
-    } semi_mask;
-
+    struct
+    {
+        sized_string_t *tmp_values;         /* Série d'octets partiels     */
+        sized_string_t *tmp_masks;          /* Masques associés            */
+    } masked;
 
 
     GScanRule *rule;                        /* Nouvelle règle à intégrer   */
@@ -66,7 +73,8 @@ typedef void *yyscan_t;
     GScanTokenNode *node;                   /* Bribe de motif à intégrer   */
     GSearchPattern *pattern;                /* Nouveau motif à considérer  */
 
-    GScanTokenModifier *modifier;
+    GScanTokenModifier *modifier;           /* Modificateur pour texte     */
+    ScanPlainNodeFlags str_flags;           /* Fanions pour texte          */
 
 
     GScanExpression *expr;                  /* Expression de condition     */
@@ -114,6 +122,11 @@ YY_DECL;
 %token NAME
 
 
+%token NOCASE "nocase"
+%token FULLWORD "fullword"
+%token PRIVATE "private"
+
+
 %token HEX_BYTES
 %token FULL_MASK
 %token SEMI_MASK
@@ -128,8 +141,8 @@ YY_DECL;
 %token BRACE_IN BRACE_OUT ASSIGN COLON
 
 
-%token PLAIN_STRING
-%token MASKED_STRING
+%token PLAIN_TEXT
+%token ESCAPED_TEXT
 
 %token TRUE_            "true"
 %token FALSE_           "false"
@@ -204,25 +217,33 @@ YY_DECL;
 
 %type <rule> rule
 
-%type <sized_cstring> PLAIN_STRING
-%type <pattern> MASKED_STRING
+%type <sized_cstring> PLAIN_TEXT
+%type <tmp_cstring> ESCAPED_TEXT
 
 %type <tmp_cstring> HEX_BYTES
 %type <unsigned_integer> FULL_MASK
-%type <semi_mask> SEMI_MASK
+%type <masked> SEMI_MASK
 
 %type <tmp_cstring> REGEX_BYTES
 
 
+
+%type <pattern> str_pattern
+
 %type <modifier> modifiers
 %type <modifier> _modifiers
 %type <modifier> chained_modifiers
 %type <modifier> mod_stage
 %type <modifier> modifier
 
+%type <str_flags> str_flags
+
+
 %type <pattern> hex_pattern
 %type <node> hex_tokens
 %type <node> hex_token
+%type <node> hex_range
+%type <node> hex_choices
 
 
 
@@ -294,13 +315,21 @@ rules : /* empty */
         //rule : RAW_RULE RULE_NAME { printf("RULE %s\n", $2); } RAW_BLOCK { printf("BLOCK: %s\n", $4); }
 
 
-external : "include" STRING
-         {
-             bool __status;
-             __status = g_content_scanner_include_resource(scanner, $2.data);
-             if (!__status)
-                 YYERROR;
-         }
+          external : "include" PLAIN_TEXT
+                   {
+                       bool __status;
+                       __status = g_content_scanner_include_resource(scanner, $2.data);
+                       if (!__status)
+                           YYERROR;
+                   }
+                   | "include" ESCAPED_TEXT
+                   {
+                       bool __status;
+                       __status = g_content_scanner_include_resource(scanner, $2->data);
+                       if (!__status)
+                           YYERROR;
+                   }
+                   ;
 
 
 rule : RAW_RULE RULE_NAME
@@ -320,11 +349,16 @@ rule : RAW_RULE RULE_NAME
 
 
 strings : /* empty */
-        | STRINGS COLON string_decls
+        | STRINGS COLON bytes_decls
         ;
 
 
-      string_decls : string_decl
+       bytes_decls : str_pattern
+                   {
+                       if ($1 == NULL) YYERROR;
+                       g_scan_rule_add_local_variable(*built_rule, $1);
+                       g_object_unref(G_OBJECT($1));
+                   }
                    | hex_pattern
                    {
                        if ($1 == NULL) YYERROR;
@@ -332,55 +366,51 @@ strings : /* empty */
                        g_object_unref(G_OBJECT($1));
                    }
                    | regex_pattern
-                   | string_decls string_decl
-                   | string_decls hex_pattern
+                   | bytes_decls str_pattern
+                   {
+                       if ($2 == NULL) YYERROR;
+                       g_scan_rule_add_local_variable(*built_rule, $2);
+                       g_object_unref(G_OBJECT($2));
+                   }
+                   | bytes_decls hex_pattern
                    {
                        if ($2 == NULL) YYERROR;
                        g_scan_rule_add_local_variable(*built_rule, $2);
                        g_object_unref(G_OBJECT($2));
                    }
-                   | string_decls regex_pattern
+                   | bytes_decls regex_pattern
                    ;
 
-string_decl : BYTES_ID ASSIGN PLAIN_STRING modifiers
-            {
-                GSearchPattern *__pat;
-                __pat = g_scan_plain_bytes_new(&$3, NULL, SPBF_NONE);
-                g_search_pattern_set_name(__pat, $1.data, $1.len);
-                g_scan_rule_add_local_variable(*built_rule, __pat);
-                g_object_unref(G_OBJECT(__pat));
-
-                /*
-                string_token_t *__token;
-                //printf("built plain %s\n", $3.cstring);
-                GBytesPattern *__pat;
-                __token = create_plain_string_token($3.cstring, $3.len);
-                printf("token: %p\n", __token);
-                __pat = g_bytes_pattern_new();
-                g_bytes_pattern_append_string(__pat, $3.cstring, $3.len);
-                g_scan_rule_add_local_variable(*built_rule, $1, G_SEARCH_PATTERN(__pat));
-                g_object_unref(G_OBJECT(__pat));
-                */
-            }
-            | BYTES_ID ASSIGN MASKED_STRING
-            {
-                printf("built %p\n", $3);
-                /*
-                GBytesPattern *__pat;
-                __pat = g_bytes_pattern_new();
-                g_search_pattern_set_name(__pat, $1.cstring, $1.len);
-                g_bytes_pattern_append_string(__pat, "\xd9\x74\x24\xf4", 4);
-                g_scan_rule_add_local_variable(*built_rule, G_SEARCH_PATTERN(__pat));
-                */
-                /*
-                GSearchPattern *__pat;
-                __pat = G_SEARCH_PATTERN($3);
-                if (g_search_pattern_prepare(__pat))
-                    g_scan_rule_add_local_variable(*built_rule, $1, __pat);
-                g_clear_object(built_pattern);
-                */
-            }
-            ;
+
+/**
+ * Définition de motif en texte brut.
+ */
+
+       str_pattern : BYTES_ID ASSIGN PLAIN_TEXT modifiers str_flags
+                   {
+                       GScanTokenNode *node;
+
+                       node = g_scan_token_node_plain_new(&$3, $4, $5);
+
+                       $$ = g_scan_plain_bytes_new(node);
+                       g_search_pattern_set_name($$, $1.data, $1.len);
+
+                       g_object_unref(G_OBJECT(node));
+
+                   }
+                   | BYTES_ID ASSIGN ESCAPED_TEXT modifiers str_flags
+                   {
+                       GScanTokenNode *node;
+
+                       node = g_scan_token_node_plain_new($3, $4, $5);
+
+                       $$ = g_scan_plain_bytes_new(node);
+                       g_search_pattern_set_name($$, $1.data, $1.len);
+
+                       g_object_unref(G_OBJECT(node));
+
+                   }
+                   ;
 
 
 /**
@@ -450,23 +480,70 @@ string_decl : BYTES_ID ASSIGN PLAIN_STRING modifiers
                    }
                    ;
 
+
+/**
+ * Prise en charge des fanions pour texte.
+ */
+
+         str_flags : /* empty */
+                   {
+                       $$ = SPNF_NONE;
+                   }
+                   | str_flags "nocase"
+                   {
+                       $$ = $1 | SPNF_CASE_INSENSITIVE;
+                   }
+                   | str_flags "fullword"
+                   {
+                       $$ = $1 | SPNF_FULLWORD;
+                   }
+                   | str_flags "private"
+                   {
+                       $$ = $1 | SPNF_PRIVATE;
+                   }
+                   ;
+
+
 /**
  * Définition de motif en hexadécimal.
  */
 
        hex_pattern : BYTES_ID ASSIGN hex_tokens
                    {
-                       $$ = g_scan_hex_bytes_new($3);
+                       $$ = g_scan_hex_bytes_new($3, false);
+                       g_search_pattern_set_name($$, $1.data, $1.len);
+                   }
+                   | BYTES_ID ASSIGN hex_tokens "private"
+                   {
+                       $$ = g_scan_hex_bytes_new($3, true);
                        g_search_pattern_set_name($$, $1.data, $1.len);
                    }
                    ;
 
         hex_tokens : hex_token
                    {
+                       if ($1 == NULL) YYERROR;
+
                        $$ = $1;
+
                    }
                    | hex_tokens hex_token
                    {
+                       if ($2 == NULL) YYERROR;
+
+                       if (!G_IS_SCAN_TOKEN_NODE_SEQUENCE($1))
+                       {
+                           $$ = g_scan_token_node_sequence_new($1);
+                           g_object_unref(G_OBJECT($1));
+                           g_scan_token_node_sequence_add(G_SCAN_TOKEN_NODE_SEQUENCE($$), $2);
+                           g_object_unref(G_OBJECT($2));
+                       }
+                       else
+                       {
+                           $$ = $1;
+                           g_scan_token_node_sequence_add(G_SCAN_TOKEN_NODE_SEQUENCE($$), $2);
+                           g_object_unref(G_OBJECT($2));
+                       }
 
                    }
                    ;
@@ -477,62 +554,115 @@ string_decl : BYTES_ID ASSIGN PLAIN_STRING modifiers
                    }
                    | FULL_MASK
                    {
-                       printf("mask len: %llu\n", $1);
+                       phys_t min;
+                       phys_t max;
+
+                       min = $1;
+                       max = $1;
+
+                       $$ = g_scan_token_node_any_new(&min, &max);
+
                    }
                    | SEMI_MASK
                    {
-                       printf("semi mask: %hhx / %hhx \n", $1.byte, $1.mask);
+                       size_t i;
+                       masked_byte_t byte;
+
+                       assert($1.tmp_values->len == $1.tmp_masks->len);
+
+                       byte.value = $1.tmp_values->data[0];
+                       byte.mask = $1.tmp_masks->data[0];
+
+                       $$ = g_scan_token_node_masked_new(&byte);
+
+                       for (i = 1; i < $1.tmp_values->len; i++)
+                       {
+                           byte.value = $1.tmp_values->data[i];
+                           byte.mask = $1.tmp_masks->data[i];
+
+                           g_scan_token_node_masked_add(G_SCAN_TOKEN_NODE_MASKED($$), &byte);
+
+                       }
+
                    }
                    | hex_range
                    {
-                       printf("...range...\n");
+                       $$ = $1;
                    }
                    | "~" hex_token
                    {
-
-                       printf("hex -- NOT --\n");
+                       $$ = g_scan_token_node_not_new($2);
 
                    }
-                   | "(" hex_token "|" hex_token ")"
+                   | "(" hex_choices ")"
                    {
-
-                       printf("hex -- OR --\n");
-
+                       $$ = $2;
                    }
                    ;
 
          hex_range : "[" "-" "]"
                    {
-
-                       printf("got inf range\n");
-
+                       $$ = g_scan_token_node_any_new(NULL, NULL);
                    }
                    | "[" UNSIGNED_INTEGER "]"
                    {
+                       phys_t min;
+                       phys_t max;
+
+                       min = $2;
+                       max = $2;
 
-                       printf("got range [%llu]\n", $2);
+                       $$ = g_scan_token_node_any_new(&min, &max);
 
                    }
                    | "[" UNSIGNED_INTEGER "-" "]"
                    {
+                       phys_t min;
+
+                       min = $2;
 
-                       printf("got range [%llu -> ]\n", $2);
+                       $$ = g_scan_token_node_any_new(&min, NULL);
 
                    }
                    | "[" "-" UNSIGNED_INTEGER "]"
                    {
+                       phys_t max;
 
-                       printf("got range [ -> %llu]\n", $3);
+                       max = $3;
+
+                       $$ = g_scan_token_node_any_new(NULL, &max);
 
                    }
                    | "[" UNSIGNED_INTEGER "-" UNSIGNED_INTEGER "]"
                    {
+                       phys_t min;
+                       phys_t max;
+
+                       min = $2;
+                       max = $4;
 
-                       printf("got range [%llu -> %llu]\n", $2, $4);
+                       $$ = g_scan_token_node_any_new(&min, &max);
 
                    }
                    ;
 
+       hex_choices : hex_token "|" hex_token
+                   {
+                       $$ = g_scan_token_node_choice_new();
+                       g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $1);
+                       g_object_unref(G_OBJECT($1));
+                       g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $3);
+                       g_object_unref(G_OBJECT($3));
+                   }
+                   | hex_choices "|" hex_token
+                   {
+                       $$ = $1;
+                       g_scan_token_node_choice_add(G_SCAN_TOKEN_NODE_CHOICE($$), $3);
+                       g_object_unref(G_OBJECT($3));
+                   }
+                   ;
+
+
 /**
  * Définition de motif sous forme d'expression régulière
  */
diff --git a/src/analysis/scan/items/Makefile.am b/src/analysis/scan/items/Makefile.am
index ce39cad..89ae41e 100644
--- a/src/analysis/scan/items/Makefile.am
+++ b/src/analysis/scan/items/Makefile.am
@@ -20,6 +20,8 @@ libanalysisscanitems_la_SOURCES =			\
 libanalysisscanitems_la_LIBADD = 			\
 	console/libanalysisscanitemsconsole.la	\
 	$(MAGIC_LIBADD)							\
+	math/libanalysisscanitemsmath.la		\
+	string/libanalysisscanitemsstring.la	\
 	time/libanalysisscanitemstime.la
 
 libanalysisscanitems_la_CFLAGS = $(LIBGOBJ_CFLAGS)
@@ -30,4 +32,4 @@ devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
 dev_HEADERS = $(libanalysisscanitems_la_SOURCES:%c=)
 
 
-SUBDIRS = console $(MAGIC_SUBDIRS) time
+SUBDIRS = console $(MAGIC_SUBDIRS) math string time
diff --git a/src/analysis/scan/items/console/log.c b/src/analysis/scan/items/console/log.c
index f4031c7..02b6207 100644
--- a/src/analysis/scan/items/console/log.c
+++ b/src/analysis/scan/items/console/log.c
@@ -228,8 +228,8 @@ static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *item,
 {
     bool result;                            /* Bilan à retourner           */
     size_t i;                               /* Boucle de parcours #1       */
-    LiteralValueType vtype;                 /* Type de valeur portée       */
     GScanLiteralExpression *literal;        /* Version plus accessible     */
+    LiteralValueType vtype;                 /* Type de valeur portée       */
     bool boolean;                           /* Valeur booléenne            */
     long long sinteger;                     /* Valeur entière signée   */
     unsigned long long uinteger;            /* Valeur entière non signée   */
@@ -275,13 +275,14 @@ static bool g_scan_console_log_function_run_call(GScanConsoleLogFunction *item,
 
             case LVT_STRING:
                 result = g_scan_literal_expression_get_string_value(literal, &string);
-                for (k = 0; k < string->len; k++)
-                {
-                    if (isprint(string->data[k]))
-                        fprintf(stderr, "%c", string->data[k]);
-                    else
-                        fprintf(stderr, "\\x%02hhx", string->data[k]);
-                }
+                if (result)
+                    for (k = 0; k < string->len; k++)
+                    {
+                        if (isprint(string->data[k]))
+                            fprintf(stderr, "%c", string->data[k]);
+                        else
+                            fprintf(stderr, "\\x%02hhx", string->data[k]);
+                    }
                 break;
 
             default:
diff --git a/src/analysis/scan/items/math/Makefile.am b/src/analysis/scan/items/math/Makefile.am
new file mode 100644
index 0000000..1f37c72
--- /dev/null
+++ b/src/analysis/scan/items/math/Makefile.am
@@ -0,0 +1,13 @@
+
+noinst_LTLIBRARIES  = libanalysisscanitemsmath.la
+
+
+libanalysisscanitemsmath_la_SOURCES =		\
+	to_string.h to_string.c
+
+libanalysisscanitemsmath_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsmath_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/math/to_string.c b/src/analysis/scan/items/math/to_string.c
new file mode 100644
index 0000000..4bb8363
--- /dev/null
+++ b/src/analysis/scan/items/math/to_string.c
@@ -0,0 +1,381 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_string.c - conversion d'une valeur entière en chaîne
+ *
+ * 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 "to_string.h"
+
+
+#include <assert.h>
+#include <stdlib.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des conversions de texte en entier. */
+static void g_scan_math_to_string_function_class_init(GScanMathToStringFunctionClass *);
+
+/* Initialise une instance de conversion de texte en entier. */
+static void g_scan_math_to_string_function_init(GScanMathToStringFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_math_to_string_function_dispose(GScanMathToStringFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_math_to_string_function_finalize(GScanMathToStringFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_math_to_string_function_get_name(const GScanMathToStringFunction *);
+
+/* Réalise la conversion d'une valeur en texte. */
+static void convert_integer_to_string(unsigned long long, unsigned long long, char **);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_math_to_string_function_run_call(GScanMathToStringFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        INTRODUCTION D'UNE NOUVELLE FONCTION                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conversion d'entier en texte. */
+G_DEFINE_TYPE(GScanMathToStringFunction, g_scan_math_to_string_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des conversions de texte en entier.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_class_init(GScanMathToStringFunctionClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GRegisteredItemClass *registered;       /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_math_to_string_function_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_math_to_string_function_finalize;
+
+    registered = G_REGISTERED_ITEM_CLASS(klass);
+
+    registered->get_name = (get_registered_item_name_fc)g_scan_math_to_string_function_get_name;
+    registered->run_call = (run_registered_item_call_fc)g_scan_math_to_string_function_run_call;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance à initialiser.                               *
+*                                                                             *
+*  Description : Initialise une instance de conversion de texte en entier.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_init(GScanMathToStringFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_dispose(GScanMathToStringFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_math_to_string_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_math_to_string_function_finalize(GScanMathToStringFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_math_to_string_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Crée une fonction de conversion de valeur entière en texte.  *
+*                                                                             *
+*  Retour      : Fonction mise en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GRegisteredItem *g_scan_math_to_string_function_new(void)
+{
+    GRegisteredItem *result;                /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, NULL);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item = élément d'appel à consulter.                          *
+*                                                                             *
+*  Description : Indique le nom associé à une expression d'évaluation.        *
+*                                                                             *
+*  Retour      : Désignation humaine de l'expression d'évaluation.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_math_to_string_function_get_name(const GScanMathToStringFunction *item)
+{
+    char *result;                           /* Désignation à retourner     */
+
+    result = strdup("to_string");
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : val  = valeur entière à traiter.                             *
+*                base = base à considérer.                                    *
+*                data = tête d'écriture à faire évoluer. [OUT]                *
+*                                                                             *
+*  Description : Réalise la conversion d'une valeur en texte.                 *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void convert_integer_to_string(unsigned long long val, unsigned long long base, char **data)
+{
+    static const char digits[16] = "0123456789abcdef";
+
+    if (val < base)
+        *((*data)++) = digits[val];
+
+    else
+    {
+        convert_integer_to_string(val / base, base, data);
+
+        *((*data)++) = digits[val % base];
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item  = élément d'appel à consulter.                         *
+*                args  = liste d'éventuels arguments fournis.                 *
+*                count = taille de cette liste.                               *
+*                ctx   = contexte de suivi de l'analyse courante.             *
+*                scope = portée courante des variables locales.               *
+*                out   = zone d'enregistrement de la résolution opérée. [OUT] *
+*                                                                             *
+*  Description : Réduit une expression à une forme plus simple.               *
+*                                                                             *
+*  Retour      : Réduction correspondante, expression déjà réduite, ou NULL.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_math_to_string_function_run_call(GScanMathToStringFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+    bool result;                            /* Bilan à retourner           */
+    GScanLiteralExpression *literal;        /* Version plus accessible     */
+    LiteralValueType vtype;                 /* Type de valeur portée       */
+    long long sval;                         /* Valeur signée obtenue       */
+    unsigned long long uval;                /* Valeur non signée obtenue   */
+    bool negative;                          /* Besoin de signe en préfixe ?*/
+    unsigned long long base;                /* Base de conversion          */
+    char *data;                             /* Chaîne "C" à constituer     */
+    char *iter;                             /* Tête d'écriture             */
+    sized_string_t string;                  /* Chaîne finale complète      */
+
+    /* Validation des arguments */
+
+    result = (count == 1 || count == 2);
+    if (!result) goto exit;
+
+    result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+    if (!result) goto exit;
+
+    literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+    vtype = g_scan_literal_expression_get_value_type(literal);
+
+    result = (vtype == LVT_SIGNED_INTEGER || vtype == LVT_UNSIGNED_INTEGER);
+    if (!result) goto exit;
+
+    if (vtype == LVT_SIGNED_INTEGER)
+    {
+        result = g_scan_literal_expression_get_signed_integer_value(literal, &sval);
+        if (!result) goto exit;
+
+        assert(sval < 0);
+
+        negative = (sval < 0);
+
+        if (negative)
+            uval = -sval;
+
+    }
+    else
+    {
+        result = g_scan_literal_expression_get_unsigned_integer_value(literal, &uval);
+        if (!result) goto exit;
+    }
+
+    if (count == 1)
+        base = 10;
+
+    else
+    {
+        result = G_IS_SCAN_LITERAL_EXPRESSION(args[1]);
+        if (!result) goto exit;
+
+        literal = G_SCAN_LITERAL_EXPRESSION(args[1]);
+
+        vtype = g_scan_literal_expression_get_value_type(literal);
+
+        result = (vtype == LVT_UNSIGNED_INTEGER);
+        if (!result) goto exit;
+
+        result = g_scan_literal_expression_get_unsigned_integer_value(literal, &base);
+        if (!result) goto exit;
+
+        result = (base == 2 || base == 8 || base == 10 || base == 16);
+        if (!result) goto exit;
+
+    }
+
+    /* Réalisation de l'opération attendue */
+
+    data = malloc((1 + 2 + 64 * 8 + 1) * sizeof(char));
+    iter = data;
+
+    if (negative)
+        *(iter++) = '-';
+
+    switch (base)
+    {
+        case 2:
+            *(iter++) = '0';
+            *(iter++) = 'b';
+            break;
+
+        case 8:
+            *(iter++) = '0';
+            break;
+
+        case 10:
+            break;
+
+        case 16:
+            *(iter++) = '0';
+            *(iter++) = 'x';
+            break;
+
+        default:
+            assert(false);
+            break;
+
+    }
+
+    convert_integer_to_string(uval, base, &iter);
+
+    string.data = data;
+    string.len = iter - data;
+
+    *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &string));
+
+    free(data);
+
+    result = true;
+
+ exit:
+
+    return result;
+
+}
diff --git a/src/analysis/scan/items/math/to_string.h b/src/analysis/scan/items/math/to_string.h
new file mode 100644
index 0000000..19f0020
--- /dev/null
+++ b/src/analysis/scan/items/math/to_string.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_string.h - prototypes pour la conversion d'une valeur entière en chaîne
+ *
+ * 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_ITEMS_MATH_TO_STRING_H
+#define _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_MATH_TO_STRING_FUNCTION            g_scan_math_to_string_function_get_type()
+#define G_SCAN_MATH_TO_STRING_FUNCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunction))
+#define G_IS_SCAN_MATH_TO_STRING_FUNCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION))
+#define G_SCAN_MATH_TO_STRING_FUNCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunctionClass))
+#define G_IS_SCAN_MATH_TO_STRING_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION))
+#define G_SCAN_MATH_TO_STRING_FUNCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MATH_TO_STRING_FUNCTION, GScanMathToStringFunctionClass))
+
+
+/* Conversion d'une valeur entière en valeur textuelle (instance) */
+typedef GRegisteredItem GScanMathToStringFunction;
+
+/* Conversion d'une valeur entière en valeur textuelle (classe) */
+typedef GRegisteredItemClass GScanMathToStringFunctionClass;
+
+
+/* Indique le type défini pour une conversion d'entier en texte. */
+GType g_scan_math_to_string_function_get_type(void);
+
+/* Crée une fonction de conversion de valeur entière en texte. */
+GRegisteredItem *g_scan_math_to_string_function_new(void);
+
+
+
+#endif  /* _ANALYSIS_SCAN_ITEMS_MATH_TO_STRING_H */
diff --git a/src/analysis/scan/items/string/Makefile.am b/src/analysis/scan/items/string/Makefile.am
new file mode 100644
index 0000000..c9ce6a3
--- /dev/null
+++ b/src/analysis/scan/items/string/Makefile.am
@@ -0,0 +1,15 @@
+
+noinst_LTLIBRARIES  = libanalysisscanitemsstring.la
+
+
+libanalysisscanitemsstring_la_SOURCES =		\
+	lower.h lower.c							\
+	to_int.h to_int.c						\
+	upper.h upper.c
+
+libanalysisscanitemsstring_la_CFLAGS = $(LIBGOBJ_CFLAGS)
+
+
+devdir = $(includedir)/chrysalide/$(subdir:src/%=core/%)
+
+dev_HEADERS = $(libanalysisscanitemsstring_la_SOURCES:%c=)
diff --git a/src/analysis/scan/items/string/lower.c b/src/analysis/scan/items/string/lower.c
new file mode 100644
index 0000000..be8b133
--- /dev/null
+++ b/src/analysis/scan/items/string/lower.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.c - bascule de lettres en minuscules
+ *
+ * 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 "lower.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des bascules de lettres en minuscules. */
+static void g_scan_string_lower_function_class_init(GScanStringLowerFunctionClass *);
+
+/* Initialise une instance de bascule de lettres en minuscules. */
+static void g_scan_string_lower_function_init(GScanStringLowerFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_lower_function_dispose(GScanStringLowerFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_lower_function_finalize(GScanStringLowerFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_lower_function_get_name(const GScanStringLowerFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_lower_function_run_call(GScanStringLowerFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        INTRODUCTION D'UNE NOUVELLE FONCTION                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+G_DEFINE_TYPE(GScanStringLowerFunction, g_scan_string_lower_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des bascules de lettres en minuscules.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_lower_function_class_init(GScanStringLowerFunctionClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GRegisteredItemClass *registered;       /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_lower_function_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_string_lower_function_finalize;
+
+    registered = G_REGISTERED_ITEM_CLASS(klass);
+
+    registered->get_name = (get_registered_item_name_fc)g_scan_string_lower_function_get_name;
+    registered->run_call = (run_registered_item_call_fc)g_scan_string_lower_function_run_call;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance à initialiser.                               *
+*                                                                             *
+*  Description : Initialise une instance de bascule de lettres en minuscules. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_lower_function_init(GScanStringLowerFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_lower_function_dispose(GScanStringLowerFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_string_lower_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_lower_function_finalize(GScanStringLowerFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_string_lower_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Constitue une fonction de bascule de lettres en minuscules.  *
+*                                                                             *
+*  Retour      : Fonction mise en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GRegisteredItem *g_scan_string_lower_function_new(void)
+{
+    GRegisteredItem *result;                /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_STRING_LOWER_FUNCTION, NULL);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item = élément d'appel à consulter.                          *
+*                                                                             *
+*  Description : Indique le nom associé à une expression d'évaluation.        *
+*                                                                             *
+*  Retour      : Désignation humaine de l'expression d'évaluation.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_string_lower_function_get_name(const GScanStringLowerFunction *item)
+{
+    char *result;                           /* Désignation à retourner     */
+
+    result = strdup("lower");
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item  = élément d'appel à consulter.                         *
+*                args  = liste d'éventuels arguments fournis.                 *
+*                count = taille de cette liste.                               *
+*                ctx   = contexte de suivi de l'analyse courante.             *
+*                scope = portée courante des variables locales.               *
+*                out   = zone d'enregistrement de la résolution opérée. [OUT] *
+*                                                                             *
+*  Description : Réduit une expression à une forme plus simple.               *
+*                                                                             *
+*  Retour      : Réduction correspondante, expression déjà réduite, ou NULL.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_string_lower_function_run_call(GScanStringLowerFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+    bool result;                            /* Bilan à retourner           */
+    GScanLiteralExpression *literal;        /* Version plus accessible     */
+    LiteralValueType vtype;                 /* Type de valeur portée       */
+    const sized_string_t *string;           /* Description du chaîne       */
+    sized_string_t new;                     /* Description transformée     */
+    size_t i;                               /* Boucle de parcours          */
+
+    /* Validation des arguments */
+
+    result = (count == 1);
+    if (!result) goto exit;
+
+    result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+    if (!result) goto exit;
+
+    literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+    vtype = g_scan_literal_expression_get_value_type(literal);
+
+    result = (vtype == LVT_STRING);
+    if (!result) goto exit;
+
+    result = g_scan_literal_expression_get_string_value(literal, &string);
+    if (!result) goto exit;
+
+    /* Réalisation de l'opération attendue */
+
+    new.data = malloc(string->len);
+    new.len = string->len;
+
+    for (i = 0; i < string->len; i++)
+        new.data[i] = tolower(string->data[i]);
+
+    *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &new));
+
+    exit_szstr(&new);
+
+ exit:
+
+    return result;
+
+}
diff --git a/src/analysis/scan/items/string/lower.h b/src/analysis/scan/items/string/lower.h
new file mode 100644
index 0000000..f844a65
--- /dev/null
+++ b/src/analysis/scan/items/string/lower.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * lower.h - prototypes pour la bascule de lettres en minuscules
+ *
+ * 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_ITEMS_STRING_LOWER_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_LOWER_FUNCTION            g_scan_string_lower_function_get_type()
+#define G_SCAN_STRING_LOWER_FUNCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunction))
+#define G_IS_SCAN_STRING_LOWER_FUNCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION))
+#define G_SCAN_STRING_LOWER_FUNCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunctionClass))
+#define G_IS_SCAN_STRING_LOWER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_LOWER_FUNCTION))
+#define G_SCAN_STRING_LOWER_FUNCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_LOWER_FUNCTION, GScanStringLowerFunctionClass))
+
+
+/* Bascule d'une suite de caractères en minuscules (instance) */
+typedef GRegisteredItem GScanStringLowerFunction;
+
+/* Bascule d'une suite de caractères en minuscules (classe) */
+typedef GRegisteredItemClass GScanStringLowerFunctionClass;
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+GType g_scan_string_lower_function_get_type(void);
+
+/* Constitue une fonction de bascule de lettres en minuscules. */
+GRegisteredItem *g_scan_string_lower_function_new(void);
+
+
+
+#endif  /* _ANALYSIS_SCAN_ITEMS_STRING_LOWER_H */
diff --git a/src/analysis/scan/items/string/to_int.c b/src/analysis/scan/items/string/to_int.c
new file mode 100644
index 0000000..8031d4d
--- /dev/null
+++ b/src/analysis/scan/items/string/to_int.c
@@ -0,0 +1,303 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_int.c - conversion d'une chaîne en valeur entière
+ *
+ * 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 "to_int.h"
+
+
+#include <stdlib.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des conversions de texte en entier. */
+static void g_scan_string_to_int_function_class_init(GScanStringToIntFunctionClass *);
+
+/* Initialise une instance de conversion de texte en entier. */
+static void g_scan_string_to_int_function_init(GScanStringToIntFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_to_int_function_dispose(GScanStringToIntFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_to_int_function_finalize(GScanStringToIntFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_to_int_function_get_name(const GScanStringToIntFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_to_int_function_run_call(GScanStringToIntFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        INTRODUCTION D'UNE NOUVELLE FONCTION                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une conversion de texte en entier. */
+G_DEFINE_TYPE(GScanStringToIntFunction, g_scan_string_to_int_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des conversions de texte en entier.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_class_init(GScanStringToIntFunctionClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GRegisteredItemClass *registered;       /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_to_int_function_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_string_to_int_function_finalize;
+
+    registered = G_REGISTERED_ITEM_CLASS(klass);
+
+    registered->get_name = (get_registered_item_name_fc)g_scan_string_to_int_function_get_name;
+    registered->run_call = (run_registered_item_call_fc)g_scan_string_to_int_function_run_call;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance à initialiser.                               *
+*                                                                             *
+*  Description : Initialise une instance de conversion de texte en entier.    *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_init(GScanStringToIntFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_dispose(GScanStringToIntFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_string_to_int_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_to_int_function_finalize(GScanStringToIntFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_string_to_int_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Crée une fonction de conversion de texte en valeur entière.  *
+*                                                                             *
+*  Retour      : Fonction mise en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GRegisteredItem *g_scan_string_to_int_function_new(void)
+{
+    GRegisteredItem *result;                /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_STRING_TO_INT_FUNCTION, NULL);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item = élément d'appel à consulter.                          *
+*                                                                             *
+*  Description : Indique le nom associé à une expression d'évaluation.        *
+*                                                                             *
+*  Retour      : Désignation humaine de l'expression d'évaluation.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_string_to_int_function_get_name(const GScanStringToIntFunction *item)
+{
+    char *result;                           /* Désignation à retourner     */
+
+    result = strdup("to_int");
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item  = élément d'appel à consulter.                         *
+*                args  = liste d'éventuels arguments fournis.                 *
+*                count = taille de cette liste.                               *
+*                ctx   = contexte de suivi de l'analyse courante.             *
+*                scope = portée courante des variables locales.               *
+*                out   = zone d'enregistrement de la résolution opérée. [OUT] *
+*                                                                             *
+*  Description : Réduit une expression à une forme plus simple.               *
+*                                                                             *
+*  Retour      : Réduction correspondante, expression déjà réduite, ou NULL.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_string_to_int_function_run_call(GScanStringToIntFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+    bool result;                            /* Bilan à retourner           */
+    GScanLiteralExpression *literal;        /* Version plus accessible     */
+    LiteralValueType vtype;                 /* Type de valeur portée       */
+    const sized_string_t *string;           /* Chaîne à convertir          */
+    unsigned long long base;                /* Base de conversion          */
+    char *data;                             /* Chaîne "C" à considérer     */
+    long long sval;                         /* Valeur signée obtenue       */
+    unsigned long long uval;                /* Valeur non signée obtenue   */
+
+    /* Validation des arguments */
+
+    result = (count == 1 || count == 2);
+    if (!result) goto exit;
+
+    result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+    if (!result) goto exit;
+
+    literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+    vtype = g_scan_literal_expression_get_value_type(literal);
+
+    result = (vtype == LVT_STRING);
+    if (!result) goto exit;
+
+    result = g_scan_literal_expression_get_string_value(literal, &string);
+    if (!result) goto exit;
+
+    if (string->len == 0) goto exit;
+
+    if (count == 1)
+        base = 0;
+
+    else
+    {
+        result = G_IS_SCAN_LITERAL_EXPRESSION(args[1]);
+        if (!result) goto exit;
+
+        literal = G_SCAN_LITERAL_EXPRESSION(args[1]);
+
+        vtype = g_scan_literal_expression_get_value_type(literal);
+
+        result = (vtype == LVT_UNSIGNED_INTEGER);
+        if (!result) goto exit;
+
+        result = g_scan_literal_expression_get_unsigned_integer_value(literal, &base);
+        if (!result) goto exit;
+
+    }
+
+    /* Réalisation de l'opération attendue */
+
+    data = strndup(string->data, string->len);
+
+    if (string->data[0] == '-')
+    {
+        sval = strtoll(data, NULL, base);
+
+        *out = G_OBJECT(g_scan_literal_expression_new(LVT_SIGNED_INTEGER, &sval));
+
+    }
+    else
+    {
+        uval = strtoll(data, NULL, base);
+
+        *out = G_OBJECT(g_scan_literal_expression_new(LVT_UNSIGNED_INTEGER, &uval));
+
+    }
+
+    free(data);
+
+ exit:
+
+    return result;
+
+}
diff --git a/src/analysis/scan/items/string/to_int.h b/src/analysis/scan/items/string/to_int.h
new file mode 100644
index 0000000..143da44
--- /dev/null
+++ b/src/analysis/scan/items/string/to_int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * to_int.h - prototypes pour la conversion d'une chaîne en valeur entière
+ *
+ * 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_ITEMS_STRING_TO_INT_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_TO_INT_FUNCTION            g_scan_string_to_int_function_get_type()
+#define G_SCAN_STRING_TO_INT_FUNCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunction))
+#define G_IS_SCAN_STRING_TO_INT_FUNCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION))
+#define G_SCAN_STRING_TO_INT_FUNCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunctionClass))
+#define G_IS_SCAN_STRING_TO_INT_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_TO_INT_FUNCTION))
+#define G_SCAN_STRING_TO_INT_FUNCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_TO_INT_FUNCTION, GScanStringToIntFunctionClass))
+
+
+/* Conversion d'une valeur textuelle en valeur entière (instance) */
+typedef GRegisteredItem GScanStringToIntFunction;
+
+/* Conversion d'une valeur textuelle en valeur entière (classe) */
+typedef GRegisteredItemClass GScanStringToIntFunctionClass;
+
+
+/* Indique le type défini pour une conversion de texte en entier. */
+GType g_scan_string_to_int_function_get_type(void);
+
+/* Crée une fonction de conversion de texte en valeur entière. */
+GRegisteredItem *g_scan_string_to_int_function_new(void);
+
+
+
+#endif  /* _ANALYSIS_SCAN_ITEMS_STRING_TO_INT_H */
diff --git a/src/analysis/scan/items/string/upper.c b/src/analysis/scan/items/string/upper.c
new file mode 100644
index 0000000..2ddd0dc
--- /dev/null
+++ b/src/analysis/scan/items/string/upper.c
@@ -0,0 +1,270 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.c - bascule de lettres en majuscules
+ *
+ * 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 "upper.h"
+
+
+#include <ctype.h>
+
+
+#include "../../item-int.h"
+#include "../../exprs/literal.h"
+
+
+
+/* ---------------------- INTRODUCTION D'UNE NOUVELLE FONCTION ---------------------- */
+
+
+/* Initialise la classe des bascules de lettres en majuscules. */
+static void g_scan_string_upper_function_class_init(GScanStringUpperFunctionClass *);
+
+/* Initialise une instance de bascule de lettres en majuscules. */
+static void g_scan_string_upper_function_init(GScanStringUpperFunction *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_string_upper_function_dispose(GScanStringUpperFunction *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_string_upper_function_finalize(GScanStringUpperFunction *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Indique le nom associé à une expression d'évaluation. */
+static char *g_scan_string_upper_function_get_name(const GScanStringUpperFunction *);
+
+/* Réduit une expression à une forme plus simple. */
+static bool g_scan_string_upper_function_run_call(GScanStringUpperFunction *, GScanExpression **, size_t, GScanContext *, GScanScope *, GObject **);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                        INTRODUCTION D'UNE NOUVELLE FONCTION                        */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+G_DEFINE_TYPE(GScanStringUpperFunction, g_scan_string_upper_function, G_TYPE_REGISTERED_ITEM);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des bascules de lettres en majuscules.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_upper_function_class_init(GScanStringUpperFunctionClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GRegisteredItemClass *registered;       /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_string_upper_function_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_string_upper_function_finalize;
+
+    registered = G_REGISTERED_ITEM_CLASS(klass);
+
+    registered->get_name = (get_registered_item_name_fc)g_scan_string_upper_function_get_name;
+    registered->run_call = (run_registered_item_call_fc)g_scan_string_upper_function_run_call;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance à initialiser.                               *
+*                                                                             *
+*  Description : Initialise une instance de bascule de lettres en majuscules. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_upper_function_init(GScanStringUpperFunction *func)
+{
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_upper_function_dispose(GScanStringUpperFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_string_upper_function_parent_class)->dispose(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : func = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_string_upper_function_finalize(GScanStringUpperFunction *func)
+{
+    G_OBJECT_CLASS(g_scan_string_upper_function_parent_class)->finalize(G_OBJECT(func));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Constitue une fonction de bascule de lettres en majuscules.  *
+*                                                                             *
+*  Retour      : Fonction mise en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GRegisteredItem *g_scan_string_upper_function_new(void)
+{
+    GRegisteredItem *result;                /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_STRING_UPPER_FUNCTION, NULL);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item = élément d'appel à consulter.                          *
+*                                                                             *
+*  Description : Indique le nom associé à une expression d'évaluation.        *
+*                                                                             *
+*  Retour      : Désignation humaine de l'expression d'évaluation.            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_string_upper_function_get_name(const GScanStringUpperFunction *item)
+{
+    char *result;                           /* Désignation à retourner     */
+
+    result = strdup("upper");
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : item  = élément d'appel à consulter.                         *
+*                args  = liste d'éventuels arguments fournis.                 *
+*                count = taille de cette liste.                               *
+*                ctx   = contexte de suivi de l'analyse courante.             *
+*                scope = portée courante des variables locales.               *
+*                out   = zone d'enregistrement de la résolution opérée. [OUT] *
+*                                                                             *
+*  Description : Réduit une expression à une forme plus simple.               *
+*                                                                             *
+*  Retour      : Réduction correspondante, expression déjà réduite, ou NULL.  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_string_upper_function_run_call(GScanStringUpperFunction *item, GScanExpression **args, size_t count, GScanContext *ctx, GScanScope *scope, GObject **out)
+{
+    bool result;                            /* Bilan à retourner           */
+    GScanLiteralExpression *literal;        /* Version plus accessible     */
+    LiteralValueType vtype;                 /* Type de valeur portée       */
+    const sized_string_t *string;           /* Description du chaîne       */
+    sized_string_t new;                     /* Description transformée     */
+    size_t i;                               /* Boucle de parcours          */
+
+    /* Validation des arguments */
+
+    result = (count == 1);
+    if (!result) goto exit;
+
+    result = G_IS_SCAN_LITERAL_EXPRESSION(args[0]);
+    if (!result) goto exit;
+
+    literal = G_SCAN_LITERAL_EXPRESSION(args[0]);
+
+    vtype = g_scan_literal_expression_get_value_type(literal);
+
+    result = (vtype == LVT_STRING);
+    if (!result) goto exit;
+
+    result = g_scan_literal_expression_get_string_value(literal, &string);
+    if (!result) goto exit;
+
+    /* Réalisation de l'opération attendue */
+
+    new.data = malloc(string->len);
+    new.len = string->len;
+
+    for (i = 0; i < string->len; i++)
+        new.data[i] = toupper(string->data[i]);
+
+    *out = G_OBJECT(g_scan_literal_expression_new(LVT_STRING, &new));
+
+    exit_szstr(&new);
+
+ exit:
+
+    return result;
+
+}
diff --git a/src/analysis/scan/items/string/upper.h b/src/analysis/scan/items/string/upper.h
new file mode 100644
index 0000000..4f6e4bc
--- /dev/null
+++ b/src/analysis/scan/items/string/upper.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * upper.h - prototypes pour la bascule de lettres en majuscules
+ *
+ * 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_ITEMS_STRING_UPPER_H
+#define _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H
+
+
+#include <glib-object.h>
+
+
+#include "../../item.h"
+
+
+
+#define G_TYPE_SCAN_STRING_UPPER_FUNCTION            g_scan_string_upper_function_get_type()
+#define G_SCAN_STRING_UPPER_FUNCTION(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunction))
+#define G_IS_SCAN_STRING_UPPER_FUNCTION(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION))
+#define G_SCAN_STRING_UPPER_FUNCTION_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunctionClass))
+#define G_IS_SCAN_STRING_UPPER_FUNCTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_STRING_UPPER_FUNCTION))
+#define G_SCAN_STRING_UPPER_FUNCTION_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_STRING_UPPER_FUNCTION, GScanStringUpperFunctionClass))
+
+
+/* Bascule d'une suite de caractères en majuscules (instance) */
+typedef GRegisteredItem GScanStringUpperFunction;
+
+/* Bascule d'une suite de caractères en majuscules (classe) */
+typedef GRegisteredItemClass GScanStringUpperFunctionClass;
+
+
+/* Indique le type défini pour une bascule de la casse d'une suite de caractères. */
+GType g_scan_string_upper_function_get_type(void);
+
+/* Constitue une fonction de bascule de lettres en majuscules. */
+GRegisteredItem *g_scan_string_upper_function_new(void);
+
+
+
+#endif  /* _ANALYSIS_SCAN_ITEMS_STRING_UPPER_H */
diff --git a/src/analysis/scan/matches/pending.c b/src/analysis/scan/matches/pending.c
index 9d1037d..03cf3f2 100644
--- a/src/analysis/scan/matches/pending.c
+++ b/src/analysis/scan/matches/pending.c
@@ -24,18 +24,80 @@
 #include "pending.h"
 
 
-#include <assert.h>
 #include <malloc.h>
+#include <stdlib.h>
 #include <string.h>
 
 
+#include "../../../common/sort.h"
+
+
+
+/* ------------------------- MEMORISATION D'UNE ZONE BORNEE ------------------------- */
+
+
+/* Compare deux couvertures bornées de correspondances. */
+static int compare_match_area(const match_area_t *, const match_area_t *);
+
+
+
+/* -------------------- CONSERVATION DE CORRESPONDANCES ETABLIES -------------------- */
+
+
 #define PENDING_ALLOC_SIZE 10
 
 
 
+
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                           MEMORISATION D'UNE ZONE BORNEE                           */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : a = pointeur vers la première zone à analyser.               *
+*                b = pointeur vers la seconde zone à analyser.                *
+*                                                                             *
+*  Description : Compare deux couvertures bornées de correspondances.         *
+*                                                                             *
+*  Retour      : Bilan de la comparaison.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static int compare_match_area(const match_area_t *a, const match_area_t *b)
+{
+    int result;                             /* Bilan à renvoyer            */
+
+    result = sort_unsigned_long_long(a->start, b->start);
+
+    if (result == 0)
+        result = sort_unsigned_long_long(a->end, b->end);
+
+    if (result == 0)
+        result = sort_unsigned_long_long(a->ttl, b->ttl);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                      CONSERVATION DE CORRESPONDANCES ETABLIES                      */
+/* ---------------------------------------------------------------------------------- */
+
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : matches = suivi de correspondances à initialiser.            *
+*                start   = première position du contenu (souvent 0).          *
+*                end     = position de fin du contenu.                        *
 *                                                                             *
 *  Description : Initialise une structure de consolidation de correspondances.*
 *                                                                             *
@@ -45,14 +107,84 @@
 *                                                                             *
 ******************************************************************************/
 
-void init_pending_matches(pending_matches_t *matches)
+void init_pending_matches(pending_matches_t *matches, const phys_t *start, const phys_t *end)
 {
+    matches->content_start = *start;
+    matches->content_end = *end;
+
     matches->areas = NULL;
     matches->allocated = 0;
     matches->used = 0;
 
     matches->initialized = false;
 
+    matches->abort = false;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dest = suivi de correspondances à initialiser. [OUT]         *
+*                src  = suivi de correspondances à copier.                    *
+*                                                                             *
+*  Description : Copie une structure de consolidation de correspondances.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void copy_pending_matches(pending_matches_t *dest, const pending_matches_t *src)
+{
+    dest->content_start = src->content_start;
+    dest->content_end = src->content_end;
+
+    dest->areas = malloc(src->used * sizeof(match_area_t));
+    dest->allocated = src->used;
+    dest->used = src->used;
+
+    memcpy(dest->areas, src->areas, src->used * sizeof(match_area_t));
+
+    dest->initialized = src->initialized;
+
+    dest->abort = src->abort;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dest = suivi de correspondances à initialiser. [OUT]         *
+*                src  = suivi de correspondances à copier.                    *
+*                                                                             *
+*  Description : Fusionne une structure de consolidation avec une autre.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void merge_pending_matches(pending_matches_t *dest, const pending_matches_t *src)
+{
+    if ((dest->used + src->used) > dest->allocated)
+    {
+        dest->allocated += src->used;
+
+        dest->areas = realloc(dest->areas, dest->allocated * sizeof(match_area_t));
+
+    }
+
+    memcpy(&dest->areas[dest->used], src->areas, src->used * sizeof(match_area_t));
+
+    dest->used += src->used;
+
+    dest->initialized |= src->initialized;
+
+    dest->abort |= src->abort;
+
 }
 
 
@@ -112,11 +244,11 @@ size_t count_pending_matches(const pending_matches_t *matches)
 *                                                                             *
 ******************************************************************************/
 
-const match_area_t *get_all_pending_matches(const pending_matches_t *matches, size_t *count)
+match_area_t * const *get_all_pending_matches(const pending_matches_t *matches, size_t *count)
 {
-    match_area_t *result;                   /* Série à renvoyer            */
+    match_area_t * const *result;           /* Série à renvoyer            */
 
-    result = matches->areas;
+    result = &matches->areas;
 
     *count = matches->used;
 
@@ -156,8 +288,15 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
     area->start = start;
     area->end = start + length;
 
+    assert(matches->content_start <= area->start);
+    assert(area->end <= matches->content_end);
+
     area->ttl = 1;
 
+    printf("[i] new match: from %llx to %llx\n",
+           (unsigned long long)area->start,
+           (unsigned long long)area->end);
+
 }
 
 
@@ -165,7 +304,7 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
 *                                                                             *
 *  Paramètres  : matches = suivi de correspondances à compléter.              *
 *                target  = indice de la zone de correspondance concernée.     *
-*                length  = taille de la zone couverte supplémentaire.         *
+*                start   = nouvelle position initiale de la zone couverte.    *
 *                                                                             *
 *  Description : Etend une zone couverte dans le suivi des correspondances.   *
 *                                                                             *
@@ -175,17 +314,19 @@ void add_pending_match(pending_matches_t *matches, phys_t start, phys_t length)
 *                                                                             *
 ******************************************************************************/
 
-void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
+void extend_pending_match_beginning(pending_matches_t *matches, size_t target, phys_t start)
 {
     match_area_t *area;                     /* Zone à actualiser           */
 
     assert(target < matches->used);
 
-    area = &matches->areas[matches->used++];
+    area = &matches->areas[target];
 
     if (area->ttl == 0)
     {
-        area->end = end;
+        assert(matches->content_start <= start);
+
+        area->start = start;
 
         area->ttl = 1;
 
@@ -194,7 +335,7 @@ void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
     {
         assert(area->ttl == 1);
 
-        add_pending_match(matches, area->start, end - area->start);
+        add_pending_match(matches, start, area->end - start);
 
     }
 
@@ -203,11 +344,11 @@ void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : matches = suivi de correspondances à consulter.              *
+*  Paramètres  : matches = suivi de correspondances à compléter.              *
 *                target  = indice de la zone de correspondance concernée.     *
-*                pos     = position à tester.                                 *
+*                length  = taille de la zone couverte supplémentaire.         *
 *                                                                             *
-*  Description : Détermine si une correspondance se termine à une position.   *
+*  Description : Etend une zone couverte dans le suivi des correspondances.   *
 *                                                                             *
 *  Retour      : -                                                            *
 *                                                                             *
@@ -215,50 +356,40 @@ void extend_pending_match(pending_matches_t *matches, size_t target, phys_t end)
 *                                                                             *
 ******************************************************************************/
 
-bool has_pending_match_ending_at(const pending_matches_t *matches, size_t target, phys_t pos)
+void extend_pending_match_ending(pending_matches_t *matches, size_t target, phys_t end)
 {
-    bool result;                            /* Statut à retourner          */
-    match_area_t *area;                     /* Couverture visée            */
+    match_area_t *area;                     /* Zone à actualiser           */
 
     assert(target < matches->used);
 
     area = &matches->areas[target];
 
-    result = (area->end == pos);
-
-    return result;
-
-}
+    if (area->ttl == 0)
+    {
+        assert(end <= matches->content_end);
 
+        printf(" -- extend same (%llu - %llu) -> new end: %llu\n",
+               (unsigned long long)area->start,
+               (unsigned long long)area->end,
+               (unsigned long long)end);
 
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : matches = suivi de correspondances à consulter.              *
-*                target  = indice de la zone de correspondance concernée.     *
-*                pos     = position à tester.                                 *
-*                min     = borne inférieure de l'espace à considérer.         *
-*                max     = borne supérieure de l'espace à considérer.         *
-*                                                                             *
-*  Description : Détermine si une correspondance se situe dans une plage.     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
+        area->end = end;
 
-bool has_pending_match_ending_between(const pending_matches_t *matches, size_t target, phys_t pos, phys_t min, phys_t max)
-{
-    bool result;                            /* Statut à retourner          */
-    match_area_t *area;                     /* Couverture visée            */
+        area->ttl = 1;
 
-    assert(target < matches->used);
+    }
+    else
+    {
+        assert(area->ttl == 1);
 
-    area = &matches->areas[target];
+        printf(" -- extend (%llu - %llu) -> new end: %llu\n",
+               (unsigned long long)area->start,
+               (unsigned long long)area->end,
+               (unsigned long long)end);
 
-    result = ((area->end + min) <= pos && pos <= (area->end + max));
+        add_pending_match(matches, area->start, end - area->start);
 
-    return result;
+    }
 
 }
 
@@ -279,6 +410,8 @@ void reset_pending_matches_ttl(pending_matches_t *matches)
 {
     size_t i;                               /* Boucle de parcours          */
 
+    assert(matches->initialized);
+
     for (i = 0; i < matches->used; i++)
         matches->areas[i].ttl = 0;
 
@@ -305,6 +438,8 @@ void purge_pending_matches(pending_matches_t *matches)
     size_t del_count;                       /* Nombre d'éléments à effacer */
     size_t i;                               /* Boucle de parcours          */
 
+    assert(matches->initialized);
+
     /**
      * Note : le code original était le suivant :
      *
@@ -378,4 +513,60 @@ void purge_pending_matches(pending_matches_t *matches)
 
     }
 
+    /* Bilan */
+
+    matches->abort = (matches->used == 0);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : matches = suivi de correspondances à finaliser.              *
+*                                                                             *
+*  Description : Trie les correspondances et retire tous les doublons.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void sort_and_filter_pending_matches(pending_matches_t *matches)
+{
+    match_area_t *last;                     /* Dernière zone conservée     */
+    size_t i;                               /* Boucle de parcours          */
+    match_area_t *cur;                      /* Zone courante dans l'analyse*/
+
+    if (matches->used > 0)
+    {
+        qsort(matches->areas, matches->used, sizeof(match_area_t), (__compar_fn_t)compare_match_area);
+
+        last = &matches->areas[0];
+
+        for (i = 1; i < matches->used; i++)
+        {
+            cur = &matches->areas[i];
+
+            if (last->start != cur->start || last->end != cur->end)
+            {
+                if ((cur - last) > 1)
+                {
+                    memmove(last + 1, cur, (matches->used - i) * sizeof(match_area_t));
+                    matches->used -= (cur - last + 1);
+                }
+
+                last = cur;
+
+            }
+
+        }
+
+        cur = &matches->areas[matches->used - 1];
+
+        if (last != cur)
+            matches->used = last - matches->areas + 1;
+
+    }
+
 }
diff --git a/src/analysis/scan/matches/pending.h b/src/analysis/scan/matches/pending.h
index 0a1fe5c..6df01c9 100644
--- a/src/analysis/scan/matches/pending.h
+++ b/src/analysis/scan/matches/pending.h
@@ -25,6 +25,7 @@
 #define _ANALYSIS_SCAN_MATCHES_PENDING_H
 
 
+#include <assert.h>
 #include <stdbool.h>
 
 
@@ -45,17 +46,28 @@ typedef struct _match_area_t
 /* Suivi de correspondances */
 typedef struct _pending_matches_t
 {
+    phys_t content_start;                   /* Point de début du contenu   */
+    phys_t content_end;                     /* Point de fin du contenu     */
+
     match_area_t *areas;                    /* Zones couvertes             */
     size_t allocated;                       /* Nombre d'allocations        */
     size_t used;                            /* Nombre de zones             */
 
     bool initialized;                       /* Etat du suivi               */
 
+    bool abort;                             /* Inutilité d'une poursuite   */
+
 } pending_matches_t;
 
 
 /* Initialise une structure de consolidation de correspondances. */
-void init_pending_matches(pending_matches_t *);
+void init_pending_matches(pending_matches_t *, const phys_t *, const phys_t *);
+
+/* Copie une structure de consolidation de correspondances. */
+void copy_pending_matches(pending_matches_t *, const pending_matches_t *);
+
+/* Fusionner une structure de consolidation avec une autre. */
+void merge_pending_matches(pending_matches_t *, const pending_matches_t *);
 
 /* Libère la mémoire utilisée par une consolidation. */
 void exit_pending_matches(pending_matches_t *);
@@ -69,26 +81,34 @@ void exit_pending_matches(pending_matches_t *);
 size_t count_pending_matches(const pending_matches_t *);
 
 /* Fournit la liste des correspondances établies à présent. */
-const match_area_t *get_all_pending_matches(const pending_matches_t *, size_t *);
+match_area_t * const  *get_all_pending_matches(const pending_matches_t *, size_t *);
 
 /*  Ajoute au suivi la définition d'une nouvelle correspondance. */
 void add_pending_match(pending_matches_t *, phys_t, phys_t);
 
 /* Etend une zone couverte dans le suivi des correspondances. */
-void extend_pending_match(pending_matches_t *, size_t, phys_t);
+void extend_pending_match_beginning(pending_matches_t *, size_t, phys_t);
 
-/* Détermine si une correspondance se situe dans une plage. */
-bool has_pending_match_ending_between(const pending_matches_t *, size_t, phys_t, phys_t, phys_t);
-
-/* Détermine si une correspondance se termine à une position. */
-bool has_pending_match_ending_at(const pending_matches_t *, size_t, phys_t);
+/* Etend une zone couverte dans le suivi des correspondances. */
+void extend_pending_match_ending(pending_matches_t *, size_t, phys_t);
 
 /* Réinitialisation à 0 tous les TTL de correspondances. */
 void reset_pending_matches_ttl(pending_matches_t *);
 
+#define keep_pending_match(p)   \
+    do                          \
+    {                           \
+        assert(p->ttl == 0);    \
+        p->ttl = 1;             \
+    }                           \
+    while (0);
+
 /* Retire toutes les correspondances sans issue pour l'analyse. */
 void purge_pending_matches(pending_matches_t *);
 
+/* Trie les correspondances et retire tous les doublons. */
+void sort_and_filter_pending_matches(pending_matches_t *);
+
 
 
 #endif  /* _ANALYSIS_SCAN_MATCHES_PENDING_H */
diff --git a/src/analysis/scan/patterns/token-int.h b/src/analysis/scan/patterns/token-int.h
index 294a3b1..f1d63f0 100644
--- a/src/analysis/scan/patterns/token-int.h
+++ b/src/analysis/scan/patterns/token-int.h
@@ -32,19 +32,17 @@
 
 
 
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-typedef bool (* enroll_token_fc) (GStringToken *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-typedef void (* check_token_fc) (const GStringToken *, GScanContext *, GBinContent *, pending_matches_t *);
-
-
 /* Encadrement d'une bribe de recherche textuelle (instance) */
 struct _GStringToken
 {
     GSearchPattern parent;                  /* A laisser en premier        */
 
     GScanTokenNode *root;                   /* Motif à rechercher          */
+    size_t slow;                            /* Surcoût du motif            */
+    bool need_backward;                     /* Besoin d'une seconde passe  */
+
+    bool fullword;                          /* Cible de mots entiers ?     */
+    bool private;                           /* Vocation privée ?           */
 
 };
 
@@ -53,14 +51,11 @@ struct _GStringTokenClass
 {
     GSearchPatternClass parent;             /* A laisser en premier        */
 
-    enroll_token_fc enroll;                 /* Inscription d'un motif      */
-    check_token_fc check;                   /* Conversion en trouvailles   */
-
 };
 
 
 /* Met en place un gestionnaire de recherche de binaire. */
-bool g_string_token_create(GStringToken *, GScanTokenNode *);
+bool g_string_token_create(GStringToken *, GScanTokenNode *, bool, bool);
 
 
 
diff --git a/src/analysis/scan/patterns/token.c b/src/analysis/scan/patterns/token.c
index cc2d87a..1b2ee8a 100644
--- a/src/analysis/scan/patterns/token.c
+++ b/src/analysis/scan/patterns/token.c
@@ -25,6 +25,7 @@
 
 
 #include <assert.h>
+#include <ctype.h>
 #include <stdio.h>
 
 
@@ -116,6 +117,11 @@ static void g_string_token_class_init(GStringTokenClass *klass)
 static void g_string_token_init(GStringToken *token)
 {
     token->root = NULL;
+    token->slow = 0;
+    token->need_backward = false;
+
+    token->fullword = false;
+    token->private = false;
 
 }
 
@@ -160,8 +166,10 @@ static void g_string_token_finalize(GStringToken *token)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : token = encadrement de motif à initialiser pleinement.       *
-*                root  = représentation du motif à recherche.                 *
+*  Paramètres  : token    = encadrement de motif à initialiser pleinement.    *
+*                root     = représentation du motif à recherche.              *
+*                fullword = limite les correspondances à des mots entiers.    *
+*                private  = donne une vocation privée au motif de recherche.  *
 *                                                                             *
 *  Description : Met en place un gestionnaire de recherche de binaire.        *
 *                                                                             *
@@ -171,7 +179,7 @@ static void g_string_token_finalize(GStringToken *token)
 *                                                                             *
 ******************************************************************************/
 
-bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
+bool g_string_token_create(GStringToken *token, GScanTokenNode *root, bool fullword, bool private)
 {
     bool result;                            /* Bilan à retourner           */
 
@@ -180,6 +188,9 @@ bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
     token->root = root;
     g_object_ref(G_OBJECT(root));
 
+    token->fullword = fullword;
+    token->private = private;
+
     return result;
 
 }
@@ -187,39 +198,74 @@ bool g_string_token_create(GStringToken *token, GScanTokenNode *root)
 
 /******************************************************************************
 *                                                                             *
-*  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). *
+*  Paramètres  : token = encadrement de motif à consulter.                    *
 *                                                                             *
-*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*  Description : Indique si seuls des mots entiers sont retenus des analyses. *
 *                                                                             *
-*  Retour      : Bilan de l'opération à renvoyer.                             *
+*  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
 *  Remarques   : -                                                            *
 *                                                                             *
 ******************************************************************************/
 
-bool g_string_token_enroll__old(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+bool g_string_token_target_fullword(const GStringToken *token)
 {
-    bool result;                            /* Statut à retourner          */
-    GStringTokenClass *class;               /* Classe de l'instance        */
+    bool result;                            /* Statut à renvoyer           */
+
+    result = token->fullword;
 
-    assert(g_engine_backend_get_atom_max_size(backend) == maxsize);
+    return result;
 
-    class = G_STRING_TOKEN_GET_CLASS(token);
+}
 
-    result = class->enroll(token, context, backend, maxsize);
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : token = encadrement de motif à consulter.                    *
+*                                                                             *
+*  Description : Détermine si le gestionnaire est à vocation privée.          *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_string_token_is_private(const GStringToken *token)
+{
+    bool result;                            /* Statut à renvoyer           */
+
+    result = token->private;
 
     return result;
 
 }
 
+
+/******************************************************************************
+*                                                                             *
+*  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). *
+*                                                                             *
+*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
 bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBackend *backend, size_t maxsize)
 {
     bool result;                            /* Statut à retourner          */
 
-    result = g_scan_token_node_enroll(token->root, context, backend, maxsize);
+    token->need_backward = g_scan_token_node_setup_tree(token->root);
+
+    result = g_scan_token_node_enroll(token->root, context, backend, maxsize, &token->slow);
+
+    printf("need backward? %d\n", token->need_backward);
 
     return result;
 
@@ -241,19 +287,59 @@ bool g_string_token_enroll(GStringToken *token, GScanContext *context, GEngineBa
 *                                                                             *
 ******************************************************************************/
 
-void g_string_token_check__old(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
 {
-    GStringTokenClass *class;               /* Classe de l'instance        */
+    size_t p;                               /* Boucle de parcours #3       */
+    match_area_t *pending;                  /* Correspondance à traiter    */
+    vmpa2t pos;                             /* Tête de lecture             */
+    const bin_t *byte;                      /* Octet à valider             */
 
-    class = G_STRING_TOKEN_GET_CLASS(token);
+    g_scan_token_node_check_forward(token->root, context, content, matches);
 
-    class->check(token, context, content, matches);
+    if (token->need_backward)
+        g_scan_token_node_check_backward(token->root, context, content, matches);
 
-}
+    sort_and_filter_pending_matches(matches);
 
-void g_string_token_check(const GStringToken *token, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
-    g_scan_token_node_check(token->root, context, content, matches, NULL);
+    if (token->fullword)
+    {
+        reset_pending_matches_ttl(matches);
+
+        for (p = 0; p < matches->used; p++)
+        {
+            pending = &matches->areas[p];
+
+            /* Validation de l'octet précédent, s'il existe */
+            if (pending->start > matches->content_start)
+            {
+                init_vmpa(&pos, pending->start - 1, VMPA_NO_VIRTUAL);
+
+                byte = g_binary_content_get_raw_access(content, &pos, 1);
+
+                if (isalnum(*byte))
+                    continue;
+
+            }
+
+            /* Validation de l'octet suivant, s'il existe */
+            if (pending->end < matches->content_end)
+            {
+                init_vmpa(&pos, pending->end, VMPA_NO_VIRTUAL);
+
+                byte = g_binary_content_get_raw_access(content, &pos, 1);
+
+                if (isalnum(*byte))
+                    continue;
+
+            }
+
+            keep_pending_match(pending);
+
+        }
+
+        purge_pending_matches(matches);
+
+    }
 
 }
 
@@ -284,6 +370,9 @@ static void g_string_token_output_to_text(const GStringToken *pattern, GScanCont
     size_t count;                           /* Quantité de cette liste     */
     size_t i;                               /* Boucle de parcours          */
 
+    if (g_string_token_is_private(pattern))
+        return;
+
     matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
 
     for (i = 0; i < count; i++)
@@ -318,6 +407,9 @@ static void g_string_token_output_to_json(const GStringToken *pattern, GScanCont
     size_t k;                               /* Boucle de parcours #2       */
     bool trailing;                          /* Virgule finale              */
 
+    if (g_string_token_is_private(pattern))
+        return;
+
     matches = g_scan_context_get_full_matches(context, G_SEARCH_PATTERN(pattern), &count);
 
     /* Nombre de correspondances */
diff --git a/src/analysis/scan/patterns/token.h b/src/analysis/scan/patterns/token.h
index 879d912..b361ecc 100644
--- a/src/analysis/scan/patterns/token.h
+++ b/src/analysis/scan/patterns/token.h
@@ -52,6 +52,12 @@ typedef struct _GStringTokenClass GStringTokenClass;
 /* Indique le type défini pour une bribe de recherche textuelle. */
 GType g_string_token_get_type(void);
 
+/* Indique si seuls des mots entiers sont retenus des analyses. */
+bool g_string_token_target_fullword(const GStringToken *);
+
+/* Détermine si le gestionnaire est à vocation privée. */
+bool g_string_token_is_private(const GStringToken *);
+
 /* Inscrit la définition d'un motif dans un moteur de recherche. */
 bool g_string_token_enroll(GStringToken *, GScanContext *, GEngineBackend *, size_t);
 
diff --git a/src/analysis/scan/patterns/tokens/Makefile.am b/src/analysis/scan/patterns/tokens/Makefile.am
index 7fb515f..f0ab3d5 100644
--- a/src/analysis/scan/patterns/tokens/Makefile.am
+++ b/src/analysis/scan/patterns/tokens/Makefile.am
@@ -8,6 +8,7 @@ libanalysisscanpatternstokens_la_SOURCES =	\
 	hex.h hex.c								\
 	node-int.h								\
 	node.h node.c							\
+	offset.h offset.c						\
 	plain-int.h								\
 	plain.h plain.c
 
diff --git a/src/analysis/scan/patterns/tokens/atom.c b/src/analysis/scan/patterns/tokens/atom.c
index fcb585d..52f239c 100644
--- a/src/analysis/scan/patterns/tokens/atom.c
+++ b/src/analysis/scan/patterns/tokens/atom.c
@@ -251,6 +251,7 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : src   = chaîne ed référence à dupliquer.                     *
+*                atom  = préselection opérée en amont.                        *
 *                count = nombre de lettres présentes.                         *
 *                                                                             *
 *  Description : Etablit la liste des cas de figures ignorant la casse.       *
@@ -261,7 +262,7 @@ void find_best_atom(const sized_binary_t *raw, size_t maxsize, tracked_scan_atom
 *                                                                             *
 ******************************************************************************/
 
-sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t count)
+sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, const tracked_scan_atom_t *atom, size_t count)
 {
     sized_binary_t *result;                 /* Liste à retourner           */
     size_t i;                               /* Boucle de parcours #1       */
@@ -274,16 +275,20 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
     size_t divisor;                         /* Taille de la découpe        */
     size_t quotient;                        /* Reste de la position        */
 
-    count *= 2;
-
     /* Création du réceptacle */
 
     result = malloc(count * sizeof(tracked_scan_atom_t));
 
+    assert(src->len == (atom->pos + atom->len + atom->rem));
+
     for (i = 0; i < count; i++)
     {
         result[i].data = malloc(src->len);
         result[i].len = src->len;
+
+        memcpy(result[i].data, src->data, atom->pos);
+        memcpy(&result[i].data[atom->pos + atom->len], &src->data[atom->pos + atom->len], atom->rem);
+
     }
 
     /* Remplissage */
@@ -294,7 +299,7 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
     check = 1;
 #endif
 
-    for (i = 0; i < src->len; i++)
+    for (i = atom->pos; i < (atom->pos + atom->len); i++)
     {
         ch = src->data[i];
 
@@ -315,8 +320,8 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
             replaced *= 2;
 
 #ifndef NDEBUG
-            check++;
-            assert((check - 1) <= count);
+            check *= 2;
+            assert(check <= count);
 #endif
 
         }
@@ -326,7 +331,51 @@ sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *src, size_t co
 
     }
 
-    assert((check - 1) == count);
+    assert(check == count);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : byte     = octet partiel à interpréter.                      *
+*                mask     = valeur du masque à appliquer.                     *
+*                produced = nombre de contenus générés. [OUT]                 *
+*                                                                             *
+*  Description : Etablit la liste des cas de figures avec un octet partiel.   *
+*                                                                             *
+*  Retour      : Liste de toutes les combinaisons possibles.                  *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+sized_binary_t *make_atoms_from_masked_byte(bin_t value, bin_t mask, size_t *produced)
+{
+    sized_binary_t *result;                 /* Liste à retourner           */
+    size_t i;                               /* Boucle de parcours #1       */
+
+    *produced = 16;
+
+    /* Création du réceptacle */
+
+    result = malloc(16 * sizeof(tracked_scan_atom_t));
+
+    /* Remplissage */
+
+    for (i = 0; i < 16; i++)
+    {
+        result[i].data = malloc(1);
+        result[i].len = 1;
+
+        if (mask == 0x0f)
+            result[i].data[0] = value | (i << 4);
+        else
+            result[i].data[0] = value | i;
+
+    }
 
     return result;
 
diff --git a/src/analysis/scan/patterns/tokens/atom.h b/src/analysis/scan/patterns/tokens/atom.h
index daa1f16..2fbc19e 100644
--- a/src/analysis/scan/patterns/tokens/atom.h
+++ b/src/analysis/scan/patterns/tokens/atom.h
@@ -58,7 +58,10 @@ int finish_quality_rating(const bitfield_t *, size_t);
 void find_best_atom(const sized_binary_t *, size_t , tracked_scan_atom_t *, size_t *);
 
 /* Etablit la liste des cas de figures ignorant la casse. */
-sized_binary_t *make_atoms_case_insensitive(const sized_binary_t *, size_t);
+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 *);
 
 /* 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 *);
diff --git a/src/analysis/scan/patterns/tokens/hex-int.h b/src/analysis/scan/patterns/tokens/hex-int.h
index f0460c8..440f693 100644
--- a/src/analysis/scan/patterns/tokens/hex-int.h
+++ b/src/analysis/scan/patterns/tokens/hex-int.h
@@ -49,7 +49,7 @@ struct _GScanHexBytesClass
 
 
 /* Met en place un gestionnaire de recherche de binaire. */
-bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *);
+bool g_scan_hex_bytes_create(GScanHexBytes *, GScanTokenNode *, bool);
 
 
 
diff --git a/src/analysis/scan/patterns/tokens/hex.c b/src/analysis/scan/patterns/tokens/hex.c
index c1cdbdf..1fda597 100644
--- a/src/analysis/scan/patterns/tokens/hex.c
+++ b/src/analysis/scan/patterns/tokens/hex.c
@@ -58,12 +58,6 @@ static void g_scan_hex_bytes_output_to_text(const GScanHexBytes *, GScanContext
 /* Affiche un motif de recherche au format JSON. */
 static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *, GScanContext *, const sized_string_t *, unsigned int, int);
 
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-//static bool g_scan_hex_bytes_enroll(GScanHexBytes *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-//static void g_scan_hex_bytes_check(const GScanHexBytes *, GScanContext *, GBinContent *, pending_matches_t *);
-
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -91,7 +85,6 @@ static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass)
 {
     GObjectClass *object;                   /* Autre version de la classe  */
     GSearchPatternClass *pattern;           /* Version de classe ancêtre   */
-    GStringTokenClass *token;               /* Version de classe parente   */
 
     object = G_OBJECT_CLASS(klass);
 
@@ -103,11 +96,6 @@ static void g_scan_hex_bytes_class_init(GScanHexBytesClass *klass)
     pattern->to_text = (output_pattern_to_text_fc)g_scan_hex_bytes_output_to_text;
     pattern->to_json = (output_pattern_to_json_fc)g_scan_hex_bytes_output_to_json;
 
-    token = G_STRING_TOKEN_CLASS(klass);
-
-    //token->enroll = (enroll_token_fc)g_scan_hex_bytes_enroll;
-    //token->check = (check_token_fc)g_scan_hex_bytes_check;
-
 }
 
 
@@ -170,6 +158,7 @@ static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : root  = représentation du motif à recherche.                 *
+*                private  = donne une vocation privée au motif de recherche.  *
 *                                                                             *
 *  Description : Construit un gestionnaire de recherche de texte brut.        *
 *                                                                             *
@@ -179,13 +168,13 @@ static void g_scan_hex_bytes_finalize(GScanHexBytes *bytes)
 *                                                                             *
 ******************************************************************************/
 
-GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
+GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root, bool private)
 {
     GSearchPattern *result;                 /* Structure à retourner       */
 
     result = g_object_new(G_TYPE_SCAN_HEX_BYTES, NULL);
 
-    if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root))
+    if (!g_scan_hex_bytes_create(G_SCAN_HEX_BYTES(result), root, private))
         g_clear_object(&result);
 
     return result;
@@ -197,6 +186,7 @@ GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
 *                                                                             *
 *  Paramètres  : bytes = encadrement de motif à initialiser pleinement.       *
 *                root  = représentation du motif à recherche.                 *
+*                private  = donne une vocation privée au motif de recherche.  *
 *                                                                             *
 *  Description : Met en place un gestionnaire de recherche de binaire.        *
 *                                                                             *
@@ -206,11 +196,11 @@ GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *root)
 *                                                                             *
 ******************************************************************************/
 
-bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root)
+bool g_scan_hex_bytes_create(GScanHexBytes *bytes, GScanTokenNode *root, bool private)
 {
     bool result;                            /* Bilan à retourner           */
 
-    result = g_string_token_create(G_STRING_TOKEN(bytes), root);
+    result = g_string_token_create(G_STRING_TOKEN(bytes), root, false, private);
 
     return result;
 
@@ -267,191 +257,3 @@ static void g_scan_hex_bytes_output_to_json(const GScanHexBytes *pattern, GScanC
     /* TODO */
 
 }
-
-#if 0
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : bytes   = 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). *
-*                                                                             *
-*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
-*                                                                             *
-*  Retour      : Bilan de l'opération à renvoyer.                             *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_scan_hex_bytes_enroll(GScanHexBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize)
-{
-    bool result;                            /* Statut à retourner          */
-    size_t i;                               /* Boucle de parcours #1       */
-    tracked_scan_atom_t atom;               /* Atome identifié             */
-    size_t letters;                         /* Nombre de lettres présentes */
-    size_t k;                               /* Boucle de parcours #2       */
-    size_t extra_count;                     /* Quantité pour l'exhaustivité*/
-    sized_binary_t *extra;                  /* Couverture supplémntaire    */
-    size_t remaining;                       /* Quantité restant à traiter  */
-
-    /* Génération d'une base de chaînes à couvrir */
-
-    if (bytes->modifier == NULL)
-    {
-        bytes->raw = malloc(sizeof(sized_binary_t));
-        bytes->count = 1;
-
-        szstrdup(&bytes[0].raw[0], &bytes->orig);
-
-        result = true;
-
-    }
-    else
-        result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count);
-
-    if (!result)
-        goto exit;
-
-    /* Préparation pour la mémorisation des atomes */
-
-    bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t));
-
-    /* Recherche des atomes */
-
-    for (i = 0; i < bytes->count; i++)
-    {
-        if (bytes->flags & SPBF_CASE_INSENSITIVE)
-        {
-            find_best_atom(&bytes->raw[i], maxsize, &atom, &letters);
-
-            if (letters == 0)
-                bytes->atoms[i] = atom;
-
-            /* Insertion des combinaisons pour couvrir toutes les casses */
-            else
-            {
-                for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
-                    ;
-
-                extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count);
-
-                remaining = bytes->count - i - 1;
-
-                bytes->count += (extra_count - 1);
-
-                bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t));
-
-                memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t));
-
-                for (k = 0; k < extra_count; k++)
-                    bytes->raw[i + k] = extra[k];
-
-                free(extra);
-
-                bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t));
-
-                for (k = 0; k < extra_count; k++)
-                    bytes->atoms[i + k] = atom;
-
-                i += extra_count - 1;
-
-            }
-
-        }
-
-        else
-            find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters);
-
-    }
-
-    /* Enregistrements en masse */
-
-
-    for (i = 0; i < bytes->count && result; i++)
-        result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]);
-
- exit:
-
-    return result;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : bytes   = 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.       *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_hex_bytes_check(const GScanHexBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
-    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 start;                           /* Point de départ             */
-    vmpa2t pos;                             /* Position dans les données   */
-    const bin_t *ptr;                       /* Accès aux données brutes    */
-    int ret;                                /* Bilan d'une comparaison     */
-
-    for (i = 0; i < bytes->count; i++)
-    {
-        raw = &bytes->raw[i];
-        atom = &bytes->atoms[i];
-
-        found = g_scan_context_get_atom_matches(context, atom->pid, &count);
-
-        for (k = 0; k < count; k++)
-        {
-            start = found[k] - atom->pos;
-
-            init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
-
-            /* Validation du contenu avant l'atome */
-
-            if (atom->pos > 0)
-            {
-                ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
-
-                ret = memcmp(raw->data, ptr, atom->pos);
-                if (ret != 0) continue;
-
-            }
-
-            /* 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);
-
-                ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
-                if (ret != 0) continue;
-
-            }
-
-            /* Mémorisation de la correspondance */
-
-            add_pending_matches(matches, start, raw->len);
-
-        }
-
-    }
-
-}
-
-#endif
diff --git a/src/analysis/scan/patterns/tokens/hex.h b/src/analysis/scan/patterns/tokens/hex.h
index 1db8eb6..fe5268c 100644
--- a/src/analysis/scan/patterns/tokens/hex.h
+++ b/src/analysis/scan/patterns/tokens/hex.h
@@ -52,7 +52,7 @@ typedef struct _GScanHexBytesClass GScanHexBytesClass;
 GType g_scan_hex_bytes_get_type(void);
 
 /* Construit un gestionnaire de recherche de texte brut. */
-GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *);
+GSearchPattern *g_scan_hex_bytes_new(GScanTokenNode *, bool);
 
 
 
diff --git a/src/analysis/scan/patterns/tokens/node-int.h b/src/analysis/scan/patterns/tokens/node-int.h
index c543cbf..091a5be 100644
--- a/src/analysis/scan/patterns/tokens/node-int.h
+++ b/src/analysis/scan/patterns/tokens/node-int.h
@@ -28,12 +28,33 @@
 #include "node.h"
 
 
+#include "offset.h"
+
+
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+typedef void (* apply_scan_token_node_flags_fc) (GScanTokenNode *, ScanTokenNodeFlags);
+
+/* 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);
+typedef bool (* enroll_scan_token_node_fc) (GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
 
 /* Transforme les correspondances locales en trouvailles. */
-typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+typedef void (* check_scan_token_node_fc) (const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, bool *);
 
 
 /* Décomposition d'un motif de recherche en atomes (instance) */
@@ -41,6 +62,8 @@ struct _GScanTokenNode
 {
     GObject parent;                         /* A laisser en premier        */
 
+    ScanTokenNodeFlags flags;               /* Propriétés particulières    */
+
 };
 
 /* Décomposition d'un motif de recherche en atomes (classe) */
@@ -48,11 +71,29 @@ struct _GScanTokenNodeClass
 {
     GObjectClass parent;                    /* A laisser en premier        */
 
+    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      */
-    check_scan_token_node_fc check;         /* Conversion en trouvailles   */
+
+    check_scan_token_node_fc check_forward; /* Conversion en trouvailles   */
+    check_scan_token_node_fc check_backward;/* Conversion en trouvailles   */
 
 };
 
 
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+
 
 #endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/node.c b/src/analysis/scan/patterns/tokens/node.c
index 224328a..1354fff 100644
--- a/src/analysis/scan/patterns/tokens/node.c
+++ b/src/analysis/scan/patterns/tokens/node.c
@@ -28,6 +28,7 @@
 
 
 #include "node-int.h"
+#include "nodes/any.h"
 
 
 
@@ -35,7 +36,7 @@
 
 
 /* Initialise la classe des éléments de décomposition. */
-static void g_scan_token_node_class_init(GScanTokenNodeClass *klass);
+static void g_scan_token_node_class_init(GScanTokenNodeClass *);
 
 /* Initialise une instance d'élément décomposant un motif. */
 static void g_scan_token_node_init(GScanTokenNode *);
@@ -95,6 +96,7 @@ static void g_scan_token_node_class_init(GScanTokenNodeClass *klass)
 
 static void g_scan_token_node_init(GScanTokenNode *node)
 {
+    node->flags = STNF_NONE;
 
 }
 
@@ -139,10 +141,148 @@ static void g_scan_token_node_finalize(GScanTokenNode *node)
 
 /******************************************************************************
 *                                                                             *
+*  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.                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *node)
+{
+    ScanTokenNodeFlags result;              /* Statut à retourner          */
+
+    result = node->flags;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node  = noeud de motif à mettre à jour.                      *
+*                flags = propriétés particulières à associer au noeud.        *
+*                                                                             *
+*  Description : Marque le noeud avec des propriétés particulières.           *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_token_node_set_flags(GScanTokenNode *node, ScanTokenNodeFlags flags)
+{
+    GScanTokenNodeClass *class;             /* Classe de l'instance        */
+
+    node->flags |= flags;
+
+    class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+    if (class->apply != NULL)
+        class->apply(node, flags);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = point de départ du parcours à effectuer.            *
+*                points = points capitaux de l'arborescence. [OUT]            *
+*                                                                             *
+*  Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+        class->visit(node, points);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = point de départ du parcours à préparer.             *
+*                                                                             *
+*  Description : Détermine et prépare les éléments clefs d'une arborescence.  *
+*                                                                             *
+*  Retour      : true si une analyse à rebourd complémentaire est requise.    *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_node_setup_tree(GScanTokenNode *node)
+{
+    bool result;                            /* Prévision à retourner       */
+    scan_tree_points_t points;              /* Repérage de points capitaux */
+    GScanTokenNode *main;                   /* Principal noeud d'opération */
+
+    /* Phase de localisation */
+
+    points.first_node = NULL;
+    points.last_node = NULL;
+
+    points.first_plain = NULL;
+    points.best_masked = NULL;
+
+    g_scan_token_node_visit(node, &points);
+
+    /* Phase d'application */
+
+    //g_scan_token_node_set_flags(points.first_node, STNF_FIRST);
+    //g_scan_token_node_set_flags(points.last_node, STNF_LAST);
+
+    if (points.first_plain != NULL)
+        main = points.first_plain;
+
+    else if (points.best_masked != NULL)
+        main = points.best_masked;
+
+    else
+        main = node;//points.first_node;
+
+    g_scan_token_node_set_flags(main, STNF_MAIN);
+
+    printf("main : %p (%s)\n", main, G_OBJECT_TYPE_NAME(main));
+
+    result = (main != node/*points.first_node*/);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
 *  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] *
 *                                                                             *
 *  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
 *                                                                             *
@@ -152,16 +292,45 @@ static void g_scan_token_node_finalize(GScanTokenNode *node)
 *                                                                             *
 ******************************************************************************/
 
-bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+bool _g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, 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);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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] *
+*                                                                             *
+*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+    bool result;                            /* Statut à retourner          */
+
     assert(g_engine_backend_get_atom_max_size(backend) == maxsize);
 
-    class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+    *slow = 0;
 
-    result = class->enroll(node, context, backend, maxsize);
+    result = _g_scan_token_node_enroll(node, context, backend, maxsize, slow);
 
     return result;
 
@@ -175,6 +344,8 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
 *                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]         *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -184,12 +355,236 @@ bool g_scan_token_node_enroll(GScanTokenNode *node, GScanContext *context, GEngi
 *                                                                             *
 ******************************************************************************/
 
-void g_scan_token_node_check(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset)
+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)
 {
     GScanTokenNodeClass *class;             /* Classe de l'instance        */
 
+    if (node->flags & STNF_MAIN)
+    {
+        //assert(*skip); //REMME
+        *skip = false;
+    }
+
+    printf("Checking forward... node=%p / %s skip=%d main=%u\n",
+           node, G_OBJECT_TYPE_NAME(node), *skip, (node->flags & STNF_MAIN) == STNF_MAIN);
+
     class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
 
-    class->check(node, context, content, matches, offset);
+    class->check_forward(node, context, content, matches, offset, not, 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.            *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_token_node_check_forward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+{
+    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 */
+    size_t pcount;                          /* Nombre de correspondances   */
+    match_area_t * const *pending_ptr;      /* Correspondances actuelles   */
+    size_t p;                               /* Boucle de parcours #2       */
+    match_area_t *pending;                  /* Correspondance à traiter    */
+    phys_t old_end;                         /* Ancien point d'arrivée      */
+    size_t o;                               /* Boucle de parcours #1       */
+    const node_offset_range_t *range;       /* Bornes d'espace à parcourir */
+    phys_t new_end;                         /* Nouveau point d'arrivée     */
+
+    init_node_search_offset(&offset);
+
+    skip = true;
+
+    _g_scan_token_node_check_forward(node, context, content, matches, &offset, false, &skip);
+
+    /**
+     * Si un décalage entre octets n'a pas été consommé,
+     * les résultats sont étendus à minima.
+     */
+
+    ranges_ptr = get_node_search_offset_ranges(&offset, &ocount);
+
+    if (ocount > 0)
+    {
+        reset_pending_matches_ttl(matches);
+
+        pending_ptr = get_all_pending_matches(matches, &pcount);
+
+        for (p = 0; p < pcount; p++)
+        {
+            pending = (*pending_ptr) + p;
+
+            old_end = pending->end;
+
+            for (o = 0; o < ocount; o++)
+            {
+                range = (*ranges_ptr) + o;
+
+                new_end = old_end + range->min;
+
+                if (new_end > matches->content_end)
+                    new_end = matches->content_end;
+
+                extend_pending_match_ending(matches, p, new_end);
+
+            }
+
+        }
+
+        /**
+         * Pas besoin de purge ici puisque tous les résultats ont été traités
+         * au moins une fois, sans condition.
+         */
+        /* purge_pending_matches(matches); */
+
+        disable_all_ranges_in_node_search_offset(&offset);
+
+    }
+
+    assert(offset.used == 0);
+
+    exit_node_search_offset(&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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    GScanTokenNodeClass *class;             /* Classe de l'instance        */
+
+    printf("Checking backward... node=%p / %s skip=%d main=%u\n",
+           node, G_OBJECT_TYPE_NAME(node), *skip, (node->flags & STNF_MAIN) == STNF_MAIN);
+
+    class = G_SCAN_TOKEN_NODE_GET_CLASS(node);
+
+    class->check_backward(node, context, content, matches, offset, not, skip);
+
+    if (node->flags & STNF_MAIN)
+    {
+        //assert(*skip); //REMME
+        *skip = false;
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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.            *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_token_node_check_backward(const GScanTokenNode *node, GScanContext *context, GBinContent *content, pending_matches_t *matches)
+{
+    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 */
+    size_t pcount;                          /* Nombre de correspondances   */
+    match_area_t * const *pending_ptr;      /* Correspondances actuelles   */
+    size_t p;                               /* Boucle de parcours #2       */
+    match_area_t *pending;                  /* Correspondance à traiter    */
+    phys_t old_start;                       /* Ancien point d'arrivée      */
+    size_t o;                               /* Boucle de parcours #1       */
+    const node_offset_range_t *range;       /* Bornes d'espace à parcourir */
+    phys_t new_start;                       /* Nouveau point d'arrivée     */
+
+    init_node_search_offset(&offset);
+
+    skip = true;
+
+    _g_scan_token_node_check_backward(node, context, content, matches, &offset, false, &skip);
+
+    /**
+     * Si un décalage entre octets n'a pas été consommé,
+     * les résultats sont étendus à minima.
+     */
+
+    ranges_ptr = get_node_search_offset_ranges(&offset, &ocount);
+
+    if (ocount > 0)
+    {
+        reset_pending_matches_ttl(matches);
+
+        pending_ptr = get_all_pending_matches(matches, &pcount);
+
+        for (p = 0; p < pcount; p++)
+        {
+            pending = (*pending_ptr) + p;
+
+            old_start = pending->start;
+
+            for (o = 0; o < ocount; o++)
+            {
+                range = (*ranges_ptr) + o;
+
+                if (old_start < range->min)
+                    new_start = 0;
+                else
+                    new_start = old_start - range->min;
+
+                if (new_start < matches->content_start)
+                    new_start = matches->content_start;
+
+                extend_pending_match_beginning(matches, p, new_start);
+
+            }
+
+        }
+
+        /**
+         * Pas besoin de purge ici puisque tous les résultats ont été traités
+         * au moins une fois, sans condition.
+         */
+        /* purge_pending_matches(matches); */
+
+        disable_all_ranges_in_node_search_offset(&offset);
+
+    }
+
+    assert(offset.used == 0);
+
+    exit_node_search_offset(&offset);
 
 }
diff --git a/src/analysis/scan/patterns/tokens/node.h b/src/analysis/scan/patterns/tokens/node.h
index 4c9eb48..a2e3b0d 100644
--- a/src/analysis/scan/patterns/tokens/node.h
+++ b/src/analysis/scan/patterns/tokens/node.h
@@ -49,28 +49,38 @@ typedef struct _GScanTokenNode GScanTokenNode;
 typedef struct _GScanTokenNodeClass GScanTokenNodeClass;
 
 
+/* Propriétés particulières pour noeud d'analyse */
+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   */
+
+} 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);
 
+/* Indique les propriétés particulières d'un noeud d'analyse. */
+ScanTokenNodeFlags g_scan_token_node_get_flags(const GScanTokenNode *);
 
-// TODO
-// validate
-// force_plain_registration // set begin/end
+/* Marque le noeud avec des propriétés particulières. */
+void g_scan_token_node_set_flags(GScanTokenNode *, ScanTokenNodeFlags);
 
+/* Détermine et prépare les éléments clefs d'une arborescence. */
+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);
+bool g_scan_token_node_enroll(GScanTokenNode *, GScanContext *, GEngineBackend *, size_t, size_t *);
 
-/* Mémorisation d'une souplesse dans les positions visées */
-typedef struct _node_search_offset_t
-{
-    phys_t min;                             /* Position minimale           */
-    phys_t max;                             /* Position maxnimale           */
-
-} node_search_offset_t;
+/* Transforme les correspondances locales en trouvailles. */
+void g_scan_token_node_check_forward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
 
 /* Transforme les correspondances locales en trouvailles. */
-void g_scan_token_node_check(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+void g_scan_token_node_check_backward(const GScanTokenNode *, GScanContext *, GBinContent *, pending_matches_t *);
 
 
 
diff --git a/src/analysis/scan/patterns/tokens/nodes/Makefile.am b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
index c20beaf..b5da1ee 100644
--- a/src/analysis/scan/patterns/tokens/nodes/Makefile.am
+++ b/src/analysis/scan/patterns/tokens/nodes/Makefile.am
@@ -3,10 +3,18 @@ noinst_LTLIBRARIES  = libanalysisscanpatternstokensnodes.la
 
 
 libanalysisscanpatternstokensnodes_la_SOURCES =	\
-	hub-int.h								\
-	hub.h hub.c								\
+	any-int.h								\
+	any.h any.c								\
+	choice-int.h							\
+	choice.h choice.c						\
+	masked-int.h							\
+	masked.h masked.c						\
+	not-int.h								\
+	not.h not.c								\
 	plain-int.h								\
-	plain.h plain.c
+	plain.h plain.c							\
+	sequence-int.h							\
+	sequence.h sequence.c
 
 libanalysisscanpatternstokensnodes_la_CFLAGS = $(LIBGOBJ_CFLAGS)
 
diff --git a/src/analysis/scan/patterns/tokens/nodes/any-int.h b/src/analysis/scan/patterns/tokens/nodes/any-int.h
new file mode 100644
index 0000000..705aab3
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any-int.h
@@ -0,0 +1,60 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any-int.h - prototypes internes pour une suite d'octets quelconques
+ *
+ * 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_TOKENS_NODES_ANY_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H
+
+
+#include "any.h"
+
+
+#include "../atom.h"
+#include "../node-int.h"
+
+
+
+/* Espace constitué d'un ou plusieurs octets quelconques (instance) */
+struct _GScanTokenNodeAny
+{
+    GScanTokenNode parent;                  /* A laisser en premier        */
+
+    phys_t min;                             /* Quantité minimale           */
+    phys_t max;                             /* Quantité maximale           */
+    bool has_max;                           /* Quantité définie ?          */
+
+};
+
+/* Espace constitué d'un ou plusieurs octets quelconques (classe) */
+struct _GScanTokenNodeAnyClass
+{
+    GScanTokenNodeClass parent;             /* A laisser en premier        */
+
+};
+
+
+/* Met en place un un noeud pointant une série d'octets. */
+bool g_scan_token_node_any_create(GScanTokenNodeAny *, const phys_t *, const phys_t *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/any.c b/src/analysis/scan/patterns/tokens/nodes/any.c
new file mode 100644
index 0000000..af2ae29
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.c
@@ -0,0 +1,425 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any.c - suite d'octets quelconques
+ *
+ * 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 "any.h"
+
+
+#include <assert.h>
+
+
+#include "any-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des séries d'octets quelconques. */
+static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *);
+
+/* Initialise une instance de série d'octets quelconques. */
+static void g_scan_token_node_any_init(GScanTokenNodeAny *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_any_dispose(GScanTokenNodeAny *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_any_finalize(GScanTokenNodeAny *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Inscrit la définition d'un motif dans un moteur de recherche. */
+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 *);
+
+/* 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 *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          DECOMPOSITION DE MOTIF RECHERCHE                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série d'octets quelconque, vide ou non. */
+G_DEFINE_TYPE(GScanTokenNodeAny, g_scan_token_node_any, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des séries d'octets quelconques.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_any_class_init(GScanTokenNodeAnyClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenNodeClass *node;              /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_any_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_token_node_any_finalize;
+
+    node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+    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;
+    node->check_backward = (check_scan_token_node_fc)g_scan_token_node_any_check_backward;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : any = instance à initialiser.                                *
+*                                                                             *
+*  Description : Initialise une instance de série d'octets quelconques.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : any = instance d'objet GLib à traiter.                       *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_any_dispose(GScanTokenNodeAny *any)
+{
+    G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->dispose(G_OBJECT(any));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : any = instance d'objet GLib à traiter.                       *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_any_finalize(GScanTokenNodeAny *any)
+{
+    G_OBJECT_CLASS(g_scan_token_node_any_parent_class)->finalize(G_OBJECT(any));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : min = éventuelle quantité minimale à retrouver.              *
+*                max = éventuelle quantité maximale à retrouver.              *
+*                                                                             *
+*  Description : Construit un noeud pointant une série d'octets quelconques.  *
+*                                                                             *
+*  Retour      : Mécanismes mis en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_any_new(const phys_t *min, const phys_t *max)
+{
+    GScanTokenNode *result;                 /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_ANY, NULL);
+
+    if (!g_scan_token_node_any_create(G_SCAN_TOKEN_NODE_ANY(result), min, max))
+        g_clear_object(&result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : any = séquence d'octets quelconques à initialiser pleinement.*
+*                min = éventuelle quantité minimale à retrouver.              *
+*                max = éventuelle quantité maximale à retrouver.              *
+*                                                                             *
+*  Description : Met en place un un noeud pointant une série d'octets.        *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_node_any_create(GScanTokenNodeAny *any, const phys_t *min, const phys_t *max)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    if (min != NULL)
+        any->min = *min;
+    else
+        any->min = 0;
+
+    if (max != NULL)
+    {
+        any->max = *max;
+
+        result = (any->min <= any->max);
+
+    }
+
+    any->has_max = (max != NULL);
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  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] *
+*                                                                             *
+*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_any_enroll(GScanTokenNodeAny *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+    bool result;                            /* Statut à retourner          */
+    bool forced;                            /* Inclusion dans un scan ?    */
+
+    result = true;
+
+    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+    if (forced)
+        *slow += (maxsize * 4);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    bool initialized;                       /* Initialisation du suivi ?   */
+    bool forced;                            /* Inclusion dans un scan ?    */
+    phys_t size;                            /* Quantité d'octets considérés*/
+    const phys_t *datasize;                 /* Taille max. à communiquer   */
+
+    if (*skip)
+        return;
+
+
+    //         $a = { [1-3] 6f }
+    // pas d'initialisation, construction de résultats avec une taille nulle
+
+
+
+    initialized = are_pending_matches_initialized(matches);
+
+    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+    size = matches->content_end - matches->content_start;
+
+    datasize = (not ? &size : NULL);
+
+    if (forced)
+    {
+        assert(!initialized);
+
+        if (node->min > size)
+            /* TODO set abort in matches */;
+
+        else
+            add_range_to_node_search_offset(offset,
+                                            matches->content_start,
+                                            matches->content_end - matches->content_start,
+                                            datasize);
+
+    }
+    else
+    {
+        assert(initialized);
+
+
+        // TODO : compléter les intervales éventuels déjà en place
+
+
+        printf("[i] create hole: %llx <-> %llx\n",
+               (unsigned long long)node->min,
+               (unsigned long long)node->max);
+
+
+
+        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);
+
+        // TODO : si dernier, virer les correspondances qui n'ont plus l'espace de fin requis
+        // -> au niveau du noeud, en fonction du flag _LAST
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+#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   */
+
+    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.
+     */
+    assert(are_pending_matches_initialized(matches));
+
+    /**
+     * 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);
+    assert(!forced);
+#endif
+
+    size = matches->content_end - matches->content_start;
+
+    if (node->min > size)
+        /* TODO set abort in matches */;
+
+    else
+    {
+        datasize = (not ? &size : NULL);
+
+        /**
+         * 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 (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);
+
+    }
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/any.h b/src/analysis/scan/patterns/tokens/nodes/any.h
new file mode 100644
index 0000000..6a5628a
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/any.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * any.h - prototypes pour une suite d'octets quelconques
+ *
+ * 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_TOKENS_NODES_ANY_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_ANY            g_scan_token_node_any_get_type()
+#define G_SCAN_TOKEN_NODE_ANY(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAny))
+#define G_IS_SCAN_TOKEN_NODE_ANY(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_ANY))
+#define G_SCAN_TOKEN_NODE_ANY_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass))
+#define G_IS_SCAN_TOKEN_NODE_ANY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_ANY))
+#define G_SCAN_TOKEN_NODE_ANY_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_ANY, GScanTokenNodeAnyClass))
+
+
+/* Espace constitué d'un ou plusieurs octets quelconques (instance) */
+typedef struct _GScanTokenNodeAny GScanTokenNodeAny;
+
+/* Espace constitué d'un ou plusieurs octets quelconques (classe) */
+typedef struct _GScanTokenNodeAnyClass GScanTokenNodeAnyClass;
+
+
+/* Indique le type défini pour une série d'octets quelconque, vide ou non. */
+GType g_scan_token_node_any_get_type(void);
+
+/* Construit un noeud pointant une série d'octets quelconques. */
+GScanTokenNode *g_scan_token_node_any_new(const phys_t *, const phys_t *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_ANY_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice-int.h b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
new file mode 100644
index 0000000..77a4058
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice-int.h - prototypes internes pour des décompositions alternatives de motif de recherche
+ *
+ * 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_TOKENS_NODES_CHOICE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H
+
+
+#include "choice.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Décompositions alternatives de motif de recherche (instance) */
+struct _GScanTokenNodeChoice
+{
+    GScanTokenNode parent;                  /* A laisser en premier        */
+
+    GScanTokenNode **children;              /* Sous-noeuds à représenter   */
+    size_t count;                           /* Taille de cette liste       */
+
+};
+
+/* Décompositions alternatives de motif de recherche (classe) */
+struct _GScanTokenNodeChoiceClass
+{
+    GScanTokenNodeClass parent;             /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.c b/src/analysis/scan/patterns/tokens/nodes/choice.c
new file mode 100644
index 0000000..df6ae45
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.c
@@ -0,0 +1,486 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice.c - décompositions alternatives de motif de recherche
+ *
+ * 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 "choice.h"
+
+
+#include "choice-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des décompositions alternatives. */
+static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *);
+
+/* Initialise une instance de décompositions alternatives. */
+static void g_scan_token_node_choice_init(GScanTokenNodeChoice *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Prend acte d'une nouvelle propriété pour le noeud. */
+static void g_scan_token_node_choice_apply_flags(GScanTokenNodeChoice *, ScanTokenNodeFlags);
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          DECOMPOSITION DE MOTIF RECHERCHE                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour des décompositions alternatives de motif de recherche. */
+G_DEFINE_TYPE(GScanTokenNodeChoice, g_scan_token_node_choice, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des décompositions alternatives.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_choice_class_init(GScanTokenNodeChoiceClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenNodeClass *node;              /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_choice_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_token_node_choice_finalize;
+
+    node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+    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->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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : choice = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une instance de décompositions alternatives.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_choice_init(GScanTokenNodeChoice *choice)
+{
+    choice->children = NULL;
+    choice->count = 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : choice = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_choice_dispose(GScanTokenNodeChoice *choice)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < choice->count; i++)
+        g_clear_object(&choice->children[i]);
+
+    G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->dispose(G_OBJECT(choice));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : choice = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_choice_finalize(GScanTokenNodeChoice *choice)
+{
+    if (choice->children != NULL)
+        free(choice->children);
+
+    G_OBJECT_CLASS(g_scan_token_node_choice_parent_class)->finalize(G_OBJECT(choice));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Construit une série de décompositions alternatives de motif. *
+*                                                                             *
+*  Retour      : Mécanismes mis en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_choice_new(void)
+{
+    GScanTokenNode *result;                 /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_CHOICE, NULL);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : choice = ensemble de noeuds à compléter.                     *
+*                node   = nouveau noeud à intégrer.                           *
+*                                                                             *
+*  Description : Ajoute un noeud à aux décompositions alternatives de motif.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_token_node_choice_add(GScanTokenNodeChoice *choice, GScanTokenNode *node)
+{
+    choice->children = realloc(choice->children, ++choice->count * sizeof(GScanTokenNode *));
+
+    choice->children[choice->count - 1] = node;
+    g_object_ref(G_OBJECT(node));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  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_choice_apply_flags(GScanTokenNodeChoice *node, ScanTokenNodeFlags flags)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < node->count; i++)
+        g_scan_token_node_set_flags(node->children[i], flags);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = point de départ du parcours à effectuer.            *
+*                points = points capitaux de l'arborescence. [OUT]            *
+*                                                                             *
+*  Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_choice_visit(GScanTokenNodeChoice *node, scan_tree_points_t *points)
+{
+    size_t first_plain_count;               /* Décompte de noeuds textuels */
+    size_t i;                               /* Boucle de parcours          */
+    scan_tree_points_t tmp_points;          /* Synthèse d'analyse locale   */
+
+    if (points->first_plain != NULL)
+        return;
+
+    first_plain_count = 0;
+
+    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;
+
+        g_scan_token_node_visit(node->children[i], &tmp_points);
+
+        if (tmp_points.first_plain != NULL)
+            first_plain_count++;
+
+    }
+
+    if (first_plain_count == node->count)
+        points->first_plain = G_SCAN_TOKEN_NODE(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] *
+*                                                                             *
+*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_choice_enroll(GScanTokenNodeChoice *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+    bool result;                            /* Statut à retourner          */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = true;
+
+    for (i = 0; i < node->count && result; i++)
+        result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    pending_matches_t init_matches;         /* Correspondances initiales   */
+    node_search_offset_t init_offset;       /* Intervales initiaux         */ 
+    size_t new_offset;                      /* Décompte d'intervales       */
+    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  */
+
+    if (*skip)
+        return;
+
+    /* Copie des contextes de départ */
+
+    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);
+
+    /* Lancement des sous-traitements */
+
+    new_offset = 0;
+
+    for (i = 0; i < node->count; i++)
+    {
+        copy_pending_matches(&tmp_matches, &init_matches);
+        copy_node_search_offset(&tmp_offset, &init_offset);
+
+        _g_scan_token_node_check_forward(node->children[i], context, content,
+                                         &tmp_matches, &tmp_offset, not, skip);
+
+        merge_pending_matches(matches, &tmp_matches);
+        merge_node_search_offset(offset, &tmp_offset);
+
+        if (tmp_offset.used > 0)
+            new_offset++;
+
+        exit_pending_matches(&tmp_matches);
+        exit_node_search_offset(&tmp_offset);
+
+    }
+
+    /* Sortie propre */
+
+    exit_pending_matches(&init_matches);
+    exit_node_search_offset(&init_offset);
+
+    /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+
+    if (new_offset != node->count)
+    {
+        assert(node->count > 1);
+        add_range_to_node_search_offset(offset, 0, 0, NULL);
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    pending_matches_t init_matches;         /* Correspondances initiales   */
+    node_search_offset_t init_offset;       /* Intervales initiaux         */ 
+    size_t new_offset;                      /* Décompte d'intervales       */
+    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  */
+
+    if (*skip)
+        return;
+
+    /* Copie des contextes de départ */
+
+    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);
+
+    /* Lancement des sous-traitements */
+
+    new_offset = 0;
+
+    for (i = 0; i < node->count; i++)
+    {
+        copy_pending_matches(&tmp_matches, &init_matches);
+        copy_node_search_offset(&tmp_offset, &init_offset);
+
+        _g_scan_token_node_check_backward(node->children[i], context, content,
+                                          &tmp_matches, &tmp_offset, not, skip);
+
+        merge_pending_matches(matches, &tmp_matches);
+        merge_node_search_offset(offset, &tmp_offset);
+
+        if (tmp_offset.used > 0)
+            new_offset++;
+
+        exit_pending_matches(&tmp_matches);
+        exit_node_search_offset(&tmp_offset);
+
+    }
+
+    /* Sortie propre */
+
+    exit_pending_matches(&init_matches);
+    exit_node_search_offset(&init_offset);
+
+    /* "Alternative" directe en cas de motif(s) non terminé(s) par un intervale */
+
+    if (new_offset != node->count)
+    {
+        assert(node->count > 1);
+        add_range_to_node_search_offset(offset, 0, 0, NULL);
+    }
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/choice.h b/src/analysis/scan/patterns/tokens/nodes/choice.h
new file mode 100644
index 0000000..e793b1e
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/choice.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * choice.h - prototypes pour des décompositions alternatives de motif de recherche
+ *
+ * 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_TOKENS_NODES_CHOICE_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_CHOICE            g_scan_token_node_choice_get_type()
+#define G_SCAN_TOKEN_NODE_CHOICE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoice))
+#define G_IS_SCAN_TOKEN_NODE_CHOICE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE))
+#define G_SCAN_TOKEN_NODE_CHOICE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass))
+#define G_IS_SCAN_TOKEN_NODE_CHOICE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_CHOICE))
+#define G_SCAN_TOKEN_NODE_CHOICE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_CHOICE, GScanTokenNodeChoiceClass))
+
+
+/* Décompositions alternatives de motif de recherche (instance) */
+typedef struct _GScanTokenNodeChoice GScanTokenNodeChoice;
+
+/* Décompositions alternatives de motif de recherche (classe) */
+typedef struct _GScanTokenNodeChoiceClass GScanTokenNodeChoiceClass;
+
+
+/* Indique le type défini pour des décompositions alternatives de motif de recherche. */
+GType g_scan_token_node_choice_get_type(void);
+
+/* Construit une série de décompositions alternatives de motif. */
+GScanTokenNode *g_scan_token_node_choice_new(void);
+
+/* Ajoute un noeud à aux décompositions alternatives de motif. */
+void g_scan_token_node_choice_add(GScanTokenNodeChoice *, GScanTokenNode *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_CHOICE_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub-int.h b/src/analysis/scan/patterns/tokens/nodes/hub-int.h
deleted file mode 100644
index df05112..0000000
--- a/src/analysis/scan/patterns/tokens/nodes/hub-int.h
+++ /dev/null
@@ -1,51 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub-int.h - prototypes internes pour un groupe de décompositions de motif de recherche en atomes assemblés
- *
- * 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_TOKENS_NODES_HUB_INT_H
-#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H
-
-
-#include "hub.h"
-
-
-#include "../node-int.h"
-
-
-
-/* Groupe de décompositions de motif de recherche en atomes (instance) */
-struct _GScanTokenNodeHub
-{
-    GScanTokenNode parent;                  /* A laisser en premier        */
-
-};
-
-/* Groupe de décompositions de motif de recherche en atomes (classe) */
-struct _GScanTokenNodeHubClass
-{
-    GScanTokenNodeClass parent;             /* A laisser en premier        */
-
-};
-
-
-
-#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub.c b/src/analysis/scan/patterns/tokens/nodes/hub.c
deleted file mode 100644
index a11531d..0000000
--- a/src/analysis/scan/patterns/tokens/nodes/hub.c
+++ /dev/null
@@ -1,150 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub.c - groupe de décompositions de motif de recherche en atomes assemblés
- *
- * 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 "hub.h"
-
-
-#include "hub-int.h"
-
-
-
-/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
-
-
-/* Initialise la classe des groupes de décompositions. */
-static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass);
-
-/* Initialise une instance de groupe de décompositions. */
-static void g_scan_token_node_hub_init(GScanTokenNodeHub *);
-
-/* Supprime toutes les références externes. */
-static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *);
-
-/* Procède à la libération totale de la mémoire. */
-static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *);
-
-
-
-/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
-
-
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                          DECOMPOSITION DE MOTIF RECHERCHE                          */
-/* ---------------------------------------------------------------------------------- */
-
-
-/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */
-G_DEFINE_TYPE(GScanTokenNodeHub, g_scan_token_node_hub, G_TYPE_SCAN_TOKEN_NODE);
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : klass = classe à initialiser.                                *
-*                                                                             *
-*  Description : Initialise la classe des groupes de décompositions.          *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_token_node_hub_class_init(GScanTokenNodeHubClass *klass)
-{
-    GObjectClass *object;                   /* Autre version de la classe  */
-
-    object = G_OBJECT_CLASS(klass);
-
-    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_hub_dispose;
-    object->finalize = (GObjectFinalizeFunc)g_scan_token_node_hub_finalize;
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : hub = instance à initialiser.                                *
-*                                                                             *
-*  Description : Initialise une instance de groupe de décompositions.         *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_token_node_hub_init(GScanTokenNodeHub *hub)
-{
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : hub = instance d'objet GLib à traiter.                       *
-*                                                                             *
-*  Description : Supprime toutes les références externes.                     *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_token_node_hub_dispose(GScanTokenNodeHub *hub)
-{
-    G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->dispose(G_OBJECT(hub));
-
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : hub = instance d'objet GLib à traiter.                       *
-*                                                                             *
-*  Description : Procède à la libération totale de la mémoire.                *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_token_node_hub_finalize(GScanTokenNodeHub *hub)
-{
-    G_OBJECT_CLASS(g_scan_token_node_hub_parent_class)->finalize(G_OBJECT(hub));
-
-}
-
-
-
-/* ---------------------------------------------------------------------------------- */
-/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
-/* ---------------------------------------------------------------------------------- */
-
-
-
-
diff --git a/src/analysis/scan/patterns/tokens/nodes/hub.h b/src/analysis/scan/patterns/tokens/nodes/hub.h
deleted file mode 100644
index b2cb0fc..0000000
--- a/src/analysis/scan/patterns/tokens/nodes/hub.h
+++ /dev/null
@@ -1,55 +0,0 @@
-
-/* Chrysalide - Outil d'analyse de fichiers binaires
- * hub.h - prototypes pour un groupe de décompositions de motif de recherche en atomes assemblés
- *
- * 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_TOKENS_NODES_HUB_H
-#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H
-
-
-#include <glib-object.h>
-
-
-#include "../node.h"
-
-
-
-#define G_TYPE_SCAN_TOKEN_NODE_HUB            g_scan_token_node_hub_get_type()
-#define G_SCAN_TOKEN_NODE_HUB(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHub))
-#define G_IS_SCAN_TOKEN_NODE_HUB(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_HUB))
-#define G_SCAN_TOKEN_NODE_HUB_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass))
-#define G_IS_SCAN_TOKEN_NODE_HUB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_HUB))
-#define G_SCAN_TOKEN_NODE_HUB_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_HUB, GScanTokenNodeHubClass))
-
-
-/* Groupe de décompositions de motif de recherche en atomes (instance) */
-typedef struct _GScanTokenNodeHub GScanTokenNodeHub;
-
-/* Groupe de décompositions de motif de recherche en atomes (classe) */
-typedef struct _GScanTokenNodeHubClass GScanTokenNodeHubClass;
-
-
-/* Indique le type défini pour un groupe de décompositions de motif d'octets à rechercher. */
-GType g_scan_token_node_hub_get_type(void);
-
-
-
-#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_HUB_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked-int.h b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
new file mode 100644
index 0000000..9eb8712
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked-int.h
@@ -0,0 +1,63 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked-int.h - prototypes internes pour la gestion d'une recherche de motif partielle
+ *
+ * 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_TOKENS_NODES_MASKED_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H
+
+
+#include "masked.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Bribe de motif partielle pour recherches (instance) */
+struct _GScanTokenNodeMasked
+{
+    GScanTokenNode parent;                  /* A laisser en premier        */
+
+    masked_byte_t *bytes;                   /* Série d'octets masqués      */
+    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 enrolled_count;                  /* Quantité avec identifiant   */
+
+};
+
+/* Bribe de motif partielle pour recherches (classe) */
+struct _GScanTokenNodeMaskedClass
+{
+    GScanTokenNodeClass parent;             /* A laisser en premier        */
+
+};
+
+
+/* Met en place une bribe de motif partielle. */
+bool g_scan_token_node_masked_create(GScanTokenNodeMasked *, const masked_byte_t *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.c b/src/analysis/scan/patterns/tokens/nodes/masked.c
new file mode 100644
index 0000000..25f0315
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.c
@@ -0,0 +1,814 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked.c - gestion d'une recherche de motif partielle
+ *
+ * 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 "masked.h"
+
+
+#include <assert.h>
+
+
+#include "masked-int.h"
+#include "../../backends/bitap.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des bribes de motif partielles. */
+static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *);
+
+/* Initialise une instance de bribe de motif partielle. */
+static void g_scan_token_node_masked_init(GScanTokenNodeMasked *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Parcourt une arborescence de noeuds et y relève des éléments. */
+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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          DECOMPOSITION DE MOTIF RECHERCHE                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour un noeud représentant une bribe partielle à retrouver. */
+G_DEFINE_TYPE(GScanTokenNodeMasked, g_scan_token_node_masked, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des bribes de motif partielles.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_masked_class_init(GScanTokenNodeMaskedClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenNodeClass *node;              /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_masked_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_token_node_masked_finalize;
+
+    node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+    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->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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : masked = instance à initialiser.                             *
+*                                                                             *
+*  Description : Initialise une instance de bribe de motif partielle.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : masked = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_masked_dispose(GScanTokenNodeMasked *masked)
+{
+    G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->dispose(G_OBJECT(masked));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : masked = instance d'objet GLib à traiter.                    *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_masked_finalize(GScanTokenNodeMasked *masked)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    if (masked->bytes != NULL)
+        free(masked->bytes);
+
+    for (i = 0; i < masked->count; i++)
+        exit_szstr(&masked->raw[i]);
+
+    if (masked->raw != NULL)
+        free(masked->raw);
+
+    if (masked->atoms != NULL)
+        free(masked->atoms);
+
+    G_OBJECT_CLASS(g_scan_token_node_masked_parent_class)->finalize(G_OBJECT(masked));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : byte = valeur masquée à intégrer.                            *
+*                                                                             *
+*  Description : Construit une bribe de motif partielle.                      *
+*                                                                             *
+*  Retour      : Mécanismes mis en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *byte)
+{
+    GScanTokenNode *result;                 /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_MASKED, NULL);
+
+    if (!g_scan_token_node_masked_create(G_SCAN_TOKEN_NODE_MASKED(result), byte))
+        g_clear_object(&result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : masked = bribe partielle à initialiser pleinement.           *
+*                byte   = valeur masquée à intégrer.                          *
+*                                                                             *
+*  Description : Met en place une bribe de motif partielle.                   *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_node_masked_create(GScanTokenNodeMasked *masked, const masked_byte_t *byte)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    g_scan_token_node_masked_add(masked, byte);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : masked = ensemble de noeuds à compléter.                     *
+*                byte = valeur masquée à intégrer.                            *
+*                                                                             *
+*  Description : Enregistre la valeur d'octet à rechercher avec son masque.   *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_token_node_masked_add(GScanTokenNodeMasked *masked, const masked_byte_t *byte)
+{
+    assert((byte->value & 0x0f) == 0 || (byte->value & 0xf0) == 0);
+
+    masked->bytes = realloc(masked->bytes, ++masked->len * sizeof(masked_byte_t));
+
+    masked->bytes[masked->len - 1] = *byte;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = point de départ du parcours à effectuer.            *
+*                points = points capitaux de l'arborescence. [OUT]            *
+*                                                                             *
+*  Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_masked_visit(GScanTokenNodeMasked *node, scan_tree_points_t *points)
+{
+    GScanTokenNodeMasked *other;            /* Concurrence à mesurer       */
+
+    if (points->best_masked == NULL)
+        points->best_masked = G_SCAN_TOKEN_NODE(node);
+
+    else
+    {
+        other = G_SCAN_TOKEN_NODE_MASKED(points->best_masked);
+
+        if (node->len > other->len)
+            points->best_masked = G_SCAN_TOKEN_NODE(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] *
+*                                                                             *
+*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_masked_enroll(GScanTokenNodeMasked *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+    bool result;                            /* Statut à retourner          */
+    bool forced;                            /* Inclusion dans un scan ?    */
+    //size_t len_to_enroll;                   /* Taille à considérer         */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = true;
+
+    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+
+    if (forced)
+    {
+        *slow += (maxsize * 2);
+
+        /**
+         * 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
+         * multiples pour une même position.
+         */
+
+        if (G_IS_BITAP_BACKEND(backend))
+        {
+            //len_to_enroll = (node->len < maxsize ? node->len : maxsize);
+
+            /* TODO */
+            assert(false);
+
+
+            node->enrolled_count = 1;
+
+        }
+
+        else
+        {
+            node->raw = make_atoms_from_masked_byte(node->bytes[0].value, node->bytes[0].mask, &node->count);
+
+            node->atoms = malloc(node->count * sizeof(tracked_scan_atom_t));
+
+            for (i = 0; i < node->count && result; i++)
+            {
+                find_best_atom(&node->raw[i], maxsize, &node->atoms[i], NULL);
+
+                result = enroll_prepared_atom(&node->raw[i], context, backend, &node->atoms[i]);
+
+            }
+
+            node->enrolled_count = node->count;
+
+        }
+
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : bytes   = octets partiels avec leur masque à interpréter.    *
+*                len     = quantité d'octets à interpréter.                   *
+*                start   = point d'analyse à respecter.                       *
+*                content = accès au contenu brut pour vérifications (optim.)  *
+*                                                                             *
+*  Description : Détermine si un contenu d'intérêt est présent à une position.*
+*                                                                             *
+*  Retour      : Bilan de l'analyse : true pour une correspondance.           *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool check_scan_token_node_masked_content(const masked_byte_t *bytes, size_t len, phys_t start, GBinContent *content)
+{
+    bool result;                            /* Bilan à retourner           */
+    vmpa2t pos;                             /* Position dans les données   */
+    const bin_t *ptr;                       /* Accès aux données brutes    */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = false;
+
+    init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
+
+    ptr = g_binary_content_get_raw_access(content, &pos, len);
+
+    for (i = 0; i < len; i++)
+    {
+        if ((ptr[i] & bytes[i].mask) != bytes[i].value)
+            break;
+    }
+
+    result = (i == len);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    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 */
+    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    */
+    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       */
+
+    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
+     * points de départ, soit des correspondances ont été établies au préalable,
+     * et il ne doit alors pas y avoir d'atome mis en place (si l'initialisation
+     * ne provient pas d'une mise en place artificielle par une inversion NOT).
+     */
+#ifndef NDEBUG
+    forced = (g_scan_token_node_get_flags(G_SCAN_TOKEN_NODE(node)) & STNF_MAIN);
+    assert((!initialized && forced) || (initialized && (!forced || not)));
+#endif
+
+    ranges_ptr = get_node_search_offset_ranges(offset, &ocount);
+
+    /* Si aucune correspondance n'a été établie */
+    if (!initialized)
+    {
+        for (i = 0; i < node->enrolled_count; i++)
+        {
+            atom = &node->atoms[i];
+
+            found = g_scan_context_get_atom_matches(context, atom->pid, &count);
+
+            for (k = 0; k < count; k++)
+            {
+                assert(atom->pos == 0);
+
+                new_begin = found[k];
+
+                /**
+                 * 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;
+                }
+
+                /**
+                 * Existe-t-il assez de place pour faire tenir le motif masqué ?
+                 */
+                if ((new_begin + node->len) > matches->content_end)
+                    continue;
+
+                status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+                if ((status && !not) || (!status && not))
+                {
+                    /**
+                     * 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);
+
+                }
+
+            }
+
+        }
+
+    }
+
+    /* Si les correspondances en place sont à confirmer et compléter */
+    else
+    {
+        reset_pending_matches_ttl(matches);
+
+        pending_ptr = get_all_pending_matches(matches, &pcount);
+
+        for (p = 0; p < pcount; p++)
+        {
+            pending = (*pending_ptr) + p;
+
+            assert(pending->end <= matches->content_end);
+
+            after = matches->content_end - pending->end;
+
+            new_begin = pending->end;
+
+            if (ocount > 0)
+            {
+                for (o = 0; o < ocount; o++)
+                {
+                    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++)
+                    {
+                        status = check_scan_token_node_masked_content(node->bytes, node->len,
+                                                                      new_begin + j, content);
+
+                        if ((status && !not) || (!status && not))
+                        {
+                            /**
+                             * 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);
+
+                            /**
+                             * 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;
+
+                        }
+
+                    }
+
+                }
+
+            }
+
+            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.
+                 */
+                if (node->len > after)
+                    continue;
+
+                new_begin = pending->end;
+
+                status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+                if ((status && !not) || (!status && not))
+                {
+                    extend_pending_match_ending(matches, p, new_begin + node->len);
+
+                    /**
+                     * Comme il n'y a qu'une seule itération par correspondance,
+                     * nul besoin de recharcher l'élément.
+                     */
+
+                }
+
+            }
+
+        }
+
+        purge_pending_matches(matches);
+
+    }
+
+    set_pending_matches_initialized(matches);
+
+    disable_all_ranges_in_node_search_offset(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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+#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  */
+
+    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.
+     */
+    assert(are_pending_matches_initialized(matches));
+
+    /**
+     * 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);
+    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++)
+    {
+        pending = (*pending_ptr) + p;
+
+        assert(matches->content_start <= pending->start);
+
+        before = pending->start - matches->content_start;
+
+        printf(" (masked) pending: %u - len=%u\n",
+               (unsigned int)pending->start, (unsigned int)node->len);
+
+        new_begin = pending->start - node->len;
+
+        if (ocount > 0)
+        {
+            for (o = 0; o < ocount; o++)
+            {
+                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, before, &min, &max))
+                {
+                    if (not)
+                        extend_pending_match_beginning(matches, p, pending->start - node->len);
+
+                    continue;
+
+                }
+
+                /**
+                 * Une recherche des différentes correspondances amont est lancée.
+                 */
+                for (j = min; j <= max; j++)
+                {
+                    status = check_scan_token_node_masked_content(node->bytes, node->len,
+                                                                  new_begin - j, content);
+
+                    if ((status && !not) || (!status && not))
+                    {
+                        /**
+                         * 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);
+
+                        /**
+                         * 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;
+
+                    }
+
+                }
+
+            }
+
+        }
+
+        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 (not)
+                    extend_pending_match_beginning(matches, p, new_begin);
+
+                continue;
+
+            }
+
+            status = check_scan_token_node_masked_content(node->bytes, node->len, new_begin, content);
+
+            printf(" (masked) found new @ %llx ? %d\n",
+                   (unsigned long long)new_begin, status);
+
+
+            if ((status && !not) || (!status && not))
+                extend_pending_match_beginning(matches, p, new_begin);
+
+        }
+
+    }
+
+    purge_pending_matches(matches);
+
+    disable_all_ranges_in_node_search_offset(offset);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/masked.h b/src/analysis/scan/patterns/tokens/nodes/masked.h
new file mode 100644
index 0000000..d1765fa
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/masked.h
@@ -0,0 +1,72 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * masked.h - prototypes pour la gestion d'une recherche de motif partielle
+ *
+ * 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_TOKENS_NODES_MASKED_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H
+
+
+#include <glib-object.h>
+
+
+#include "../atom.h"
+#include "../node.h"
+#include "../../../../../arch/archbase.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_MASKED            g_scan_token_node_masked_get_type()
+#define G_SCAN_TOKEN_NODE_MASKED(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMasked))
+#define G_IS_SCAN_TOKEN_NODE_MASKED(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED))
+#define G_SCAN_TOKEN_NODE_MASKED_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass))
+#define G_IS_SCAN_TOKEN_NODE_MASKED_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_MASKED))
+#define G_SCAN_TOKEN_NODE_MASKED_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_MASKED, GScanTokenNodeMaskedClass))
+
+
+/* Bribe de motif partielle pour recherches (instance) */
+typedef struct _GScanTokenNodeMasked GScanTokenNodeMasked;
+
+/* Bribe de motif partielle pour recherches (classe) */
+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);
+
+/* Construit une bribe de motif partielle. */
+GScanTokenNode *g_scan_token_node_masked_new(const masked_byte_t *);
+
+/* Enregistre la valeur d'octet à rechercher avec son masque. */
+void g_scan_token_node_masked_add(GScanTokenNodeMasked *, const masked_byte_t *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_MASKED_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/not-int.h b/src/analysis/scan/patterns/tokens/nodes/not-int.h
new file mode 100644
index 0000000..5f92afd
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not-int.h
@@ -0,0 +1,57 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not-int.h - prototypes internes pour l'inversion de résultats de correspondances établis
+ *
+ * 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_TOKENS_NODES_NOT_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H
+
+
+#include "not.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Inversion de résultats de correspondances établis (instance) */
+struct _GScanTokenNodeNot
+{
+    GScanTokenNode parent;                  /* A laisser en premier        */
+
+    GScanTokenNode *child;                  /* Sous-noeud à considérer     */
+
+};
+
+/* Inversion de résultats de correspondances établis (classe) */
+struct _GScanTokenNodeNotClass
+{
+    GScanTokenNodeClass parent;             /* A laisser en premier        */
+
+};
+
+
+/* Met en place une inversion de résultats de correspondances. */
+bool g_scan_token_node_not_create(GScanTokenNodeNot *, GScanTokenNode *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/not.c b/src/analysis/scan/patterns/tokens/nodes/not.c
new file mode 100644
index 0000000..c54a66f
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not.c
@@ -0,0 +1,364 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not.c - inversion de résultats de correspondances établis
+ *
+ * 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 "not.h"
+
+
+#include "not-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des inversions de correspondances. */
+static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *);
+
+/* Initialise une instance d'inversion de correspondances. */
+static void g_scan_token_node_not_init(GScanTokenNodeNot *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_not_dispose(GScanTokenNodeNot *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_not_finalize(GScanTokenNodeNot *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* 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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          DECOMPOSITION DE MOTIF RECHERCHE                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une inversion des résultats de correspondances. */
+G_DEFINE_TYPE(GScanTokenNodeNot, g_scan_token_node_not, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des inversions de correspondances.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_not_class_init(GScanTokenNodeNotClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenNodeClass *node;              /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_not_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_token_node_not_finalize;
+
+    node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+    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->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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : not = instance à initialiser.                                *
+*                                                                             *
+*  Description : Initialise une instance d'inversion de correspondances.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_not_init(GScanTokenNodeNot *not)
+{
+    not->child = NULL;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : not = instance d'objet GLib à traiter.                       *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_not_dispose(GScanTokenNodeNot *not)
+{
+    g_clear_object(&not->child);
+
+    G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->dispose(G_OBJECT(not));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : not = instance d'objet GLib à traiter.                       *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_not_finalize(GScanTokenNodeNot *not)
+{
+    G_OBJECT_CLASS(g_scan_token_node_not_parent_class)->finalize(G_OBJECT(not));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : child = noeud dont les résultats sont à écarter.             *
+*                                                                             *
+*  Description : Construit une inversion de résultats de correspondances.     *
+*                                                                             *
+*  Retour      : Mécanismes mis en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *child)
+{
+    GScanTokenNode *result;                 /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_NOT, NULL);
+
+    if (!g_scan_token_node_not_create(G_SCAN_TOKEN_NODE_NOT(result), child))
+        g_clear_object(&result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : not   = encadrement d'inversion à initialiser pleinement.    *
+*                child = noeud dont les résultats sont à écarter.             *
+*                                                                             *
+*  Description : Met en place une inversion de résultats de correspondances.  *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_node_not_create(GScanTokenNodeNot *not, GScanTokenNode *child)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    not->child = child;
+    g_object_ref(G_OBJECT(child));
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = point de départ du parcours à effectuer.            *
+*                points = points capitaux de l'arborescence. [OUT]            *
+*                                                                             *
+*  Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_not_visit(GScanTokenNodeNot *node, scan_tree_points_t *points)
+{
+    g_scan_token_node_visit(node->child, points);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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] *
+*                                                                             *
+*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_not_enroll(GScanTokenNodeNot *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+    bool result;                            /* Statut à retourner          */
+
+    result = _g_scan_token_node_enroll(node->child, context, backend, maxsize, slow);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    bool initialized;                       /* Initialisation du suivi ?   */
+    phys_t i;                               /* Boucle de parcours          */
+
+
+    /*
+
+      ?????????????????????????
+
+
+    if (*skip)
+        return;
+    */
+
+
+
+    initialized = are_pending_matches_initialized(matches);
+
+
+    printf("TOTO......(init done? %d)\n", initialized);
+
+
+
+    if (!initialized)
+    {
+        for (i = matches->content_start; i < matches->content_end; i++)
+            add_pending_match(matches, i, 0);
+
+        set_pending_matches_initialized(matches);
+
+    }
+
+    _g_scan_token_node_check_forward(node->child, context, content, matches, offset, !not, 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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+
+
+
+    if (*skip)
+        return;
+
+
+
+    printf("TODO\n");
+    assert(0);
+
+
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/not.h b/src/analysis/scan/patterns/tokens/nodes/not.h
new file mode 100644
index 0000000..58630e8
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/not.h
@@ -0,0 +1,59 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * not.h - prototypes pour l'inversion de résultats de correspondances établis
+ *
+ * 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_TOKENS_NODES_NOT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+#include "../../../../../arch/archbase.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_NOT            g_scan_token_node_not_get_type()
+#define G_SCAN_TOKEN_NODE_NOT(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNot))
+#define G_IS_SCAN_TOKEN_NODE_NOT(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_NOT))
+#define G_SCAN_TOKEN_NODE_NOT_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass))
+#define G_IS_SCAN_TOKEN_NODE_NOT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_NOT))
+#define G_SCAN_TOKEN_NODE_NOT_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_NOT, GScanTokenNodeNotClass))
+
+
+/* Inversion de résultats de correspondances établis (instance) */
+typedef struct _GScanTokenNodeNot GScanTokenNodeNot;
+
+/* Inversion de résultats de correspondances établis (classe) */
+typedef struct _GScanTokenNodeNotClass GScanTokenNodeNotClass;
+
+
+/* Indique le type défini pour une inversion des résultats de correspondances. */
+GType g_scan_token_node_not_get_type(void);
+
+/* Construit une inversion de résultats de correspondances. */
+GScanTokenNode *g_scan_token_node_not_new(GScanTokenNode *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_NOT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain-int.h b/src/analysis/scan/patterns/tokens/nodes/plain-int.h
index a38359d..2077c6f 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain-int.h
+++ b/src/analysis/scan/patterns/tokens/nodes/plain-int.h
@@ -28,8 +28,8 @@
 #include "plain.h"
 
 
-#include "../node-int.h"
 #include "../atom.h"
+#include "../node-int.h"
 
 
 
@@ -56,7 +56,7 @@ struct _GScanTokenNodePlainClass
 };
 
 
-/* Met en place un un noeud représentant un motif textuel. */
+/* Met en place un noeud représentant un motif textuel. */
 bool g_scan_token_node_plain_create(GScanTokenNodePlain *, const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags);
 
 
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.c b/src/analysis/scan/patterns/tokens/nodes/plain.c
index ee87c73..5a7f976 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.c
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.c
@@ -24,7 +24,11 @@
 #include "plain.h"
 
 
+#include <assert.h>
+
+
 #include "plain-int.h"
+#include "../../../../../common/extstr.h"
 
 
 
@@ -32,7 +36,7 @@
 
 
 /* Initialise la classe des noeuds pour motif textuel. */
-static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass);
+static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *);
 
 /* Initialise une instance de noeud pour motif textuel. */
 static void g_scan_token_node_plain_init(GScanTokenNodePlain *);
@@ -48,14 +52,20 @@ static void g_scan_token_node_plain_finalize(GScanTokenNodePlain *);
 /* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
 
 
+/* 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 );
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *, GScanContext *, GEngineBackend *, size_t, size_t *);
 
 /* 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 *, phys_t, GBinContent *);
+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_plain_bytes_check(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, const node_search_offset_t *);
+static void g_scan_token_node_plain_check_forward(const GScanTokenNodePlain *, GScanContext *, GBinContent *, pending_matches_t *, node_search_offset_t *, bool, 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 *);
 
 
 
@@ -92,8 +102,10 @@ static void g_scan_token_node_plain_class_init(GScanTokenNodePlainClass *klass)
 
     node = G_SCAN_TOKEN_NODE_CLASS(klass);
 
+    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->check = (check_scan_token_node_fc)g_scan_plain_bytes_check;
+    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;
 
 }
 
@@ -112,6 +124,8 @@ 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;
@@ -203,6 +217,7 @@ GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTok
 
 }
 
+
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : plain    = encadrement de motif à initialiser pleinement.    *
@@ -210,7 +225,7 @@ GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *text, GScanTok
 *                modifier = transformateur éventuel à solliciter.             *
 *                flags    = particularités à prendre en considération.        *
 *                                                                             *
-*  Description : Met en place un un noeud représentant un motif textuel.      *
+*  Description : Met en place un noeud représentant un motif textuel.         *
 *                                                                             *
 *  Retour      : Bilan de l'opération.                                        *
 *                                                                             *
@@ -239,6 +254,29 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
 }
 
 
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : plain = noeud de motif textuel à consulter.                  *
+*                                                                             *
+*  Description : Indique les propriétés particulières d'un noeud de texte.    *
+*                                                                             *
+*  Retour      : Propriétés particulières associées au noeud.                 *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *plain)
+{
+    ScanPlainNodeFlags result;              /* Statut à retourner          */
+
+    result = plain->flags;
+
+    return result;
+
+}
+
+
 
 /* ---------------------------------------------------------------------------------- */
 /*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
@@ -247,10 +285,32 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
 
 /******************************************************************************
 *                                                                             *
+*  Paramètres  : node   = point de départ du parcours à effectuer.            *
+*                points = points capitaux de l'arborescence. [OUT]            *
+*                                                                             *
+*  Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_plain_visit(GScanTokenNodePlain *node, scan_tree_points_t *points)
+{
+    if (points->first_plain == NULL)
+        points->first_plain = G_SCAN_TOKEN_NODE(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] *
 *                                                                             *
 *  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
 *                                                                             *
@@ -260,7 +320,7 @@ bool g_scan_token_node_plain_create(GScanTokenNodePlain *plain, const sized_bina
 *                                                                             *
 ******************************************************************************/
 
-static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize)
+static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
 {
     bool result;                            /* Statut à retourner          */
     size_t i;                               /* Boucle de parcours #1       */
@@ -312,13 +372,14 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
             if (letters == 0)
                 node->atoms[i] = atom;
 
-            /* Insertion des combinaisons pour couvrir toutes les casses */
+            /* Insertion des nouvelles combinaisons pour couvrir toutes les casses */
             else
             {
-                for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
+                /* extra_count = 2^letters */
+                for (k = 1, extra_count = 2; k < letters; k++, extra_count *= 2)
                     ;
 
-                extra = make_atoms_case_insensitive(&node->raw[i], extra_count);
+                extra = make_atoms_case_insensitive(&node->raw[i], &atom, extra_count);
 
                 remaining = node->count - i - 1;
 
@@ -333,7 +394,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
 
                 free(extra);
 
-                node->atoms = realloc(node->raw, node->count * sizeof(tracked_scan_atom_t));
+                node->atoms = realloc(node->atoms, node->count * sizeof(tracked_scan_atom_t));
 
                 for (k = 0; k < extra_count; k++)
                     node->atoms[i + k] = atom;
@@ -365,6 +426,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
 *                                                                             *
 *  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.       *
 *                start   = point d'analyse à respecter.                       *
 *                content = accès au contenu brut pour vérifications (optim.)  *
 *                                                                             *
@@ -376,7 +438,7 @@ static bool g_scan_token_node_plain_enroll(GScanTokenNodePlain *node, GScanConte
 *                                                                             *
 ******************************************************************************/
 
-static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, phys_t start, GBinContent *content)
+static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const tracked_scan_atom_t *atom, bool nocase, phys_t start, GBinContent *content)
 {
     bool result;                            /* Bilan à retourner           */
     vmpa2t pos;                             /* Position dans les données   */
@@ -393,7 +455,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
     {
         ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
 
-        ret = memcmp(raw->data, ptr, atom->pos);
+        if (nocase)
+            ret = memcasecmp(raw->data, ptr, atom->pos);
+        else
+            ret = memcmp(raw->data, ptr, atom->pos);
+
         if (ret != 0) goto done;
 
     }
@@ -406,7 +472,11 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
 
         ptr = g_binary_content_get_raw_access(content, &pos, atom->rem);
 
-        ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
+        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;
 
     }
@@ -427,6 +497,8 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
 *                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]         *
 *                                                                             *
 *  Description : Transforme les correspondances locales en trouvailles.       *
 *                                                                             *
@@ -436,22 +508,33 @@ static bool check_scan_token_node_plain_content(const sized_binary_t *raw, const
 *                                                                             *
 ******************************************************************************/
 
-static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanContext *context, GBinContent *content, pending_matches_t *matches, const node_search_offset_t *offset)
+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)
 {
     bool initialized;                       /* Initialisation du suivi ?   */
+    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 start;                           /* Point de départ             */
+    phys_t new_begin;                       /* Nouveau départ à tester     */
     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    */
+
+    if (*skip)
+        return;
 
     initialized = are_pending_matches_initialized(matches);
 
+    nocase = (node->flags & SPNF_CASE_INSENSITIVE);
+
+    get_node_search_offset_ranges(offset, &ocount);
+
     for (i = 0; i < node->count; i++)
     {
         raw = &node->raw[i];
@@ -463,28 +546,34 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
         {
             for (k = 0; k < count; k++)
             {
-                start = found[k] - atom->pos;
+                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 (offset != NULL)
+                if (ocount > 0)
                 {
-                    if (start < offset->min || start > offset->max)
+                    if (!does_node_search_offset_include_pos_forward(offset, 0, new_begin))
+                    {
+                        if (not)
+                            add_pending_match(matches, new_begin, raw->len);
+
                         continue;
+
+                    }
                 }
 
-                status = check_scan_token_node_plain_content(raw, atom, start, content);
+                status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
 
-                if (status)
+                if ((status && !not) || (!status && not))
                     /**
                      * Il ne peut y avoir qu'une seule séquence d'octets à un même
-                     * emplacement, donc le couple (start, len) enregistré est
+                     * emplacement, donc le couple (new_begin, len) enregistré est
                      * unique.
                      */
-                    add_pending_match(matches, start, raw->len);
+                    add_pending_match(matches, new_begin, raw->len);
 
             }
 
@@ -494,12 +583,17 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
         {
             reset_pending_matches_ttl(matches);
 
-            pcount = count_pending_matches(matches);
+            pending_ptr = get_all_pending_matches(matches, &pcount);
 
             for (p = 0; p < pcount; p++)
+            {
+                pending = (*pending_ptr) + p;
+
+                assert(matches->content_start <= pending->start);
+
                 for (k = 0; k < count; k++)
                 {
-                    start = found[k] - atom->pos;
+                    new_begin = found[k] - atom->pos;
 
                     /**
                      * Si bornes de tolérance il y a, on valide la position.
@@ -507,20 +601,52 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
                      * Sinon les correspondances passées et actuelle doivent
                      * être jointes.
                      */
-                    if (offset != NULL)
+                    if (ocount > 0)
                     {
-                        if (!has_pending_match_ending_between(matches, p, start, offset->min, offset->max))
+                        if (!does_node_search_offset_include_pos_forward(offset, pending->end, new_begin))
+                        {
+                            if (not)
+                            {
+                                extend_pending_match_ending(matches, p, pending->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;
+
+                            }
+
                             continue;
+
+                        }
                     }
                     else
                     {
-                        if (!has_pending_match_ending_at(matches, p, start))
+                        if (pending->end != new_begin)
+                        {
+                            if (not)
+                            {
+                                extend_pending_match_ending(matches, p, pending->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;
+
+                            }
+
                             continue;
+
+                        }
                     }
 
-                    status = check_scan_token_node_plain_content(raw, atom, start, content);
+                    status = check_scan_token_node_plain_content(raw, atom, nocase, new_begin, content);
 
-                    if (status)
+                    if ((status && !not) || (!status && not))
                     {
                         /**
                          * Même si une base de couples uniques est assurée,
@@ -559,18 +685,28 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
 
                         /**
                          * La seconde situation est prise en compte par la fonction
-                         * extend_pending_match() 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.
+                         * 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.
                          */
 
-                        extend_pending_match(matches, p, start + raw->len);
+                        extend_pending_match_ending(matches, p, new_begin + 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;
 
                     }
 
                 }
 
+            }
+
             purge_pending_matches(matches);
 
         }
@@ -579,4 +715,42 @@ static void g_scan_plain_bytes_check(const GScanTokenNodePlain *node, GScanConte
 
     set_pending_matches_initialized(matches);
 
+    disable_all_ranges_in_node_search_offset(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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+
+
+
+    if (*skip)
+        return;
+
+
+
+    printf("TODO\n");
+    assert(0);
+
+
+
 }
diff --git a/src/analysis/scan/patterns/tokens/nodes/plain.h b/src/analysis/scan/patterns/tokens/nodes/plain.h
index 33e7feb..c8f3920 100644
--- a/src/analysis/scan/patterns/tokens/nodes/plain.h
+++ b/src/analysis/scan/patterns/tokens/nodes/plain.h
@@ -52,9 +52,16 @@ typedef struct _GScanTokenNodePlainClass GScanTokenNodePlainClass;
 /* Propriétés d'un élément textuel à rechercher */
 typedef enum _ScanPlainNodeFlags
 {
-    SPNF_NONE             = 0x0,            /* Aucune particularité        */
-    SPNF_CASE_INSENSITIVE = 0x1,            /* Ignorance de la casse       */
-    SPNF_FULL_WORD        = 0x2,            /* Recherche de mot entier     */
+    SPNF_NONE             = (0 << 0),       /* Aucune particularité        */
+    SPNF_CASE_INSENSITIVE = (1 << 0),       /* Ignorance de la casse       */
+
+    /**
+     * Les deux propriétés suivantes sont récupérées et traitées
+     * au niveau du Token propriétaire.
+     */
+
+    SPNF_FULLWORD         = (1 << 1),       /* Recherche de mot entier     */
+    SPNF_PRIVATE          = (1 << 2),       /* Marque privative            */
 
 } ScanPlainNodeFlags;
 
@@ -65,6 +72,9 @@ GType g_scan_token_node_plain_get_type(void);
 /* Construit un noeud représentant un motif textuel. */
 GScanTokenNode *g_scan_token_node_plain_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainNodeFlags);
 
+/* Indique les propriétés particulières d'un noeud de texte. */
+ScanPlainNodeFlags g_scan_token_node_plain_get_flags(const GScanTokenNodePlain *);
+
 
 
 #endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_PLAIN_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence-int.h b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h
new file mode 100644
index 0000000..f0ea6ae
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence-int.h
@@ -0,0 +1,58 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence-int.h - prototypes internes pour des décompositions séquentielles de motif de recherche
+ *
+ * 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_TOKENS_NODES_SEQUENCE_INT_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H
+
+
+#include "sequence.h"
+
+
+#include "../node-int.h"
+
+
+
+/* Décompositions séquentielles de motif de recherche (instance) */
+struct _GScanTokenNodeSequence
+{
+    GScanTokenNode parent;                  /* A laisser en premier        */
+
+    GScanTokenNode **children;              /* Sous-noeuds à représenter   */
+    size_t count;                           /* Taille de cette liste       */
+
+};
+
+/* Décompositions séquentielles de motif de recherche (classe) */
+struct _GScanTokenNodeSequenceClass
+{
+    GScanTokenNodeClass parent;             /* A laisser en premier        */
+
+};
+
+
+/* Met en place une série de décompositions séquentielles. */
+bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *, GScanTokenNode *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_INT_H */
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.c b/src/analysis/scan/patterns/tokens/nodes/sequence.c
new file mode 100644
index 0000000..ad332fc
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.c
@@ -0,0 +1,360 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence.c - décompositions séquentielles de motif de recherche
+ *
+ * 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 "sequence.h"
+
+
+#include "sequence-int.h"
+
+
+
+/* ------------------------ DECOMPOSITION DE MOTIF RECHERCHE ------------------------ */
+
+
+/* Initialise la classe des décompositions séquentielles. */
+static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *);
+
+/* Initialise une instance de décompositions séquentielles. */
+static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* 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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                          DECOMPOSITION DE MOTIF RECHERCHE                          */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */
+G_DEFINE_TYPE(GScanTokenNodeSequence, g_scan_token_node_sequence, G_TYPE_SCAN_TOKEN_NODE);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des décompositions séquentielles.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_class_init(GScanTokenNodeSequenceClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenNodeClass *node;              /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_token_node_sequence_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_token_node_sequence_finalize;
+
+    node = G_SCAN_TOKEN_NODE_CLASS(klass);
+
+    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->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;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : sequence = instance à initialiser.                           *
+*                                                                             *
+*  Description : Initialise une instance de décompositions séquentielles.     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_init(GScanTokenNodeSequence *sequence)
+{
+    sequence->children = NULL;
+    sequence->count = 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : sequence = instance d'objet GLib à traiter.                  *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_dispose(GScanTokenNodeSequence *sequence)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < sequence->count; i++)
+        g_clear_object(&sequence->children[i]);
+
+    G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->dispose(G_OBJECT(sequence));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : sequence = instance d'objet GLib à traiter.                  *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_finalize(GScanTokenNodeSequence *sequence)
+{
+    if (sequence->children != NULL)
+        free(sequence->children);
+
+    G_OBJECT_CLASS(g_scan_token_node_sequence_parent_class)->finalize(G_OBJECT(sequence));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : child    = noeud dont les résultats sont à écarter.          *
+*                                                                             *
+*  Description : Construit une série de décompositions séquentielles de motif.*
+*                                                                             *
+*  Retour      : Mécanismes mis en place.                                     *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *child)
+{
+    GScanTokenNode *result;                 /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, NULL);
+
+    if (!g_scan_token_node_sequence_create(G_SCAN_TOKEN_NODE_SEQUENCE(result), child))
+        g_clear_object(&result);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : sequence = décompositions à initialiser pleinement.          *
+*                child    = noeud dont les résultats sont à écarter.          *
+*                                                                             *
+*  Description : Met en place une série de décompositions séquentielles.      *
+*                                                                             *
+*  Retour      : Bilan de l'opération.                                        *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool g_scan_token_node_sequence_create(GScanTokenNodeSequence *sequence, GScanTokenNode *child)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    result = true;
+
+    g_scan_token_node_sequence_add(sequence, child);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : sequence = ensemble de noeuds à compléter.                   *
+*                child  = nouveau noeud à intégrer.                           *
+*                                                                             *
+*  Description : Ajoute un noeud à aux décompositions séquentielles de motif. *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_token_node_sequence_add(GScanTokenNodeSequence *sequence, GScanTokenNode *child)
+{
+    sequence->children = realloc(sequence->children, ++sequence->count * sizeof(GScanTokenNode *));
+
+    sequence->children[sequence->count - 1] = child;
+    g_object_ref(G_OBJECT(child));
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : node   = point de départ du parcours à effectuer.            *
+*                points = points capitaux de l'arborescence. [OUT]            *
+*                                                                             *
+*  Description : Parcourt une arborescence de noeuds et y relève des éléments.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_token_node_sequence_visit(GScanTokenNodeSequence *node, scan_tree_points_t *points)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < node->count; i++)
+        g_scan_token_node_visit(node->children[i], points);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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] *
+*                                                                             *
+*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
+*                                                                             *
+*  Retour      : Bilan de l'opération à renvoyer.                             *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_token_node_sequence_enroll(GScanTokenNodeSequence *node, GScanContext *context, GEngineBackend *backend, size_t maxsize, size_t *slow)
+{
+    bool result;                            /* Statut à retourner          */
+    size_t i;                               /* Boucle de parcours          */
+
+    result = true;
+
+    for (i = 0; i < node->count && result; i++)
+        result = _g_scan_token_node_enroll(node->children[i], context, backend, maxsize, slow);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    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);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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]         *
+*                                                                             *
+*  Description : Transforme les correspondances locales en trouvailles.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+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)
+{
+    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);
+
+}
diff --git a/src/analysis/scan/patterns/tokens/nodes/sequence.h b/src/analysis/scan/patterns/tokens/nodes/sequence.h
new file mode 100644
index 0000000..fc181c6
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/nodes/sequence.h
@@ -0,0 +1,61 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * sequence.h - prototypes pour des décompositions séquentielles de motif de recherche
+ *
+ * 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_TOKENS_NODES_SEQUENCE_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H
+
+
+#include <glib-object.h>
+
+
+#include "../node.h"
+
+
+
+#define G_TYPE_SCAN_TOKEN_NODE_SEQUENCE            g_scan_token_node_sequence_get_type()
+#define G_SCAN_TOKEN_NODE_SEQUENCE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequence))
+#define G_IS_SCAN_TOKEN_NODE_SEQUENCE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE))
+#define G_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass))
+#define G_IS_SCAN_TOKEN_NODE_SEQUENCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE))
+#define G_SCAN_TOKEN_NODE_SEQUENCE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_TOKEN_NODE_SEQUENCE, GScanTokenNodeSequenceClass))
+
+
+/* Décompositions séquentielles de motif de recherche (instance) */
+typedef struct _GScanTokenNodeSequence GScanTokenNodeSequence;
+
+/* Décompositions séquentielles de motif de recherche (classe) */
+typedef struct _GScanTokenNodeSequenceClass GScanTokenNodeSequenceClass;
+
+
+/* Indique le type défini pour des décompositions séquentielles de motif de recherche. */
+GType g_scan_token_node_sequence_get_type(void);
+
+/* Construit une série de décompositions séquentielles de motif. */
+GScanTokenNode *g_scan_token_node_sequence_new(GScanTokenNode *);
+
+/* Ajoute un noeud à aux décompositions séquentielles de motif. */
+void g_scan_token_node_sequence_add(GScanTokenNodeSequence *, GScanTokenNode *);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_NODES_SEQUENCE_H */
diff --git a/src/analysis/scan/patterns/tokens/offset.c b/src/analysis/scan/patterns/tokens/offset.c
new file mode 100644
index 0000000..010ec67
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.c
@@ -0,0 +1,352 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * offset.c - décomposition d'un motif de recherche en atomes assemblés
+ *
+ * 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 "offset.h"
+
+
+#include <assert.h>
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : range     = bornes décrivant un espace quelconque.           *
+*                available = espace restant disponible.                       *
+*                min       = point de départ pour parcourir une zone. [OUT]   *
+*                max       = point d'arrivée pour parcourir une zone. [OUT]   *
+*                                                                             *
+*  Description : Fournit les bornes d'une zone à analyser.                    *
+*                                                                             *
+*  Retour      : true si assez d'espace est disponible, false sinon.          *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool get_node_offset_range(const node_offset_range_t *range, phys_t len, phys_t available, phys_t *min, phys_t *max)
+{
+    bool result;                            /* Bilan à retourner           */
+
+    if ((len + range->min) > available)
+        result = false;
+
+    else
+    {
+        result = true;
+
+        *min = range->min;
+        *max = range->max;
+
+        if ((len + *max) > available)
+        {
+            *max = available - len;
+            assert(*max >= *min);
+        }
+
+    }
+
+    return result;
+
+}
+
+
+
+
+
+
+
+
+
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : offset = suivi de tolérances bornées à initialiser.          *
+*                                                                             *
+*  Description : Initialise une mémorisation d'intervales de tolérance.       *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void init_node_search_offset(node_search_offset_t *offset)
+{
+    offset->ranges = NULL;
+    offset->allocated = 0;
+
+    offset->gen_ptr = NULL;
+
+    offset->used = 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dest = suivi de tolérances bornées à initialiser. [OUT]      *
+*                src  = suivi de tolérances bornées à copier.                 *
+*                                                                             *
+*  Description : Copie une mémorisation d'intervales entre positions.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void copy_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src)
+{
+    init_node_search_offset(dest);
+
+    switch (src->used)
+    {
+        case 0:
+            dest->gen_ptr = NULL;
+            break;
+
+        case 1:
+            dest->range = src->range;
+            dest->gen_ptr = &dest->range;
+            break;
+
+        default:
+            dest->ranges = malloc(src->used * sizeof(node_offset_range_t));
+            memcpy(dest->ranges, src->ranges, src->used * sizeof(node_offset_range_t));
+            dest->gen_ptr = dest->ranges;;
+            break;
+
+    }
+
+    dest->used = src->used;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : dest = suivi de tolérances bornées à initialiser. [OUT]      *
+*                src  = suivi de tolérances bornées à copier.                 *
+*                                                                             *
+*  Description : Fusionne une mémorisation d'intervales entre positions.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void merge_node_search_offset(node_search_offset_t *dest, const node_search_offset_t *src)
+{
+    node_offset_range_t * const *list;      /* Liste d'intervales à copier */
+    size_t i;                               /* Boucle de parcours          */
+
+    if ((dest->used + src->used) > 1 && (dest->used + src->used) > dest->allocated)
+    {
+        dest->allocated += src->used;
+
+        dest->ranges = realloc(dest->ranges, dest->allocated * sizeof(node_offset_range_t));
+
+    }
+
+    list = get_node_search_offset_ranges(src, (size_t []){ 0 });
+
+    for (i = 0; i < src->used; i++)
+        add_range_to_node_search_offset(dest, (*list)[i].min, (*list)[i].max, NULL);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : offset = suivi de tolérances bornées à terminer.             *
+*                                                                             *
+*  Description : Met fin à une mémorisation d'intervales de tolérance.        *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void exit_node_search_offset(node_search_offset_t *offset)
+{
+    if (offset->ranges != NULL)
+        free(offset->ranges);
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  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   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+node_offset_range_t * const *get_node_search_offset_ranges(const node_search_offset_t *offset, size_t *count)
+{
+    node_offset_range_t * const *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.          *
+*                datasize = taille maximale pour définir une inversion NOT.   *
+*                                                                             *
+*  Description : Ajoute un nouvel espace borné aux décalages tolérés.         *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void add_range_to_node_search_offset(node_search_offset_t *offset, phys_t min, phys_t max, const phys_t *datasize)
+{
+    bool not;                               /* Traduction de la taille     */
+    size_t needed;                          /* Nombre d'emplacements requis*/
+
+    not = (datasize != NULL);
+
+    /* Si le réceptacle unique peut être employé... */
+    if (offset->used == 0 && !not)
+    {
+        offset->range.min = min;
+        offset->range.max = max;
+
+        offset->used = 1;
+
+        offset->gen_ptr = &offset->range;
+
+    }
+
+    /* Sinon le groupe dynamique est sollicité */
+    else
+    {
+        needed = offset->used + (not ? 2 : 1);
+
+        if (needed > offset->allocated)
+        {
+            offset->ranges = realloc(offset->ranges, needed * sizeof(node_offset_range_t));
+            offset->allocated = needed;
+        }
+
+        /* Bascule d'un éventuel intervale courant */
+        if (offset->used == 1)
+        {
+            offset->ranges[0].min = offset->range.min;
+            offset->ranges[0].max = offset->range.max;
+        }
+
+        if (not)
+        {
+            if (min > 0)
+            {
+                offset->ranges[offset->used].min = 0;
+                offset->ranges[offset->used].max = min - 1;
+
+                offset->used++;
+
+            }
+
+            if ((max + 1) < *datasize)
+            {
+                offset->ranges[offset->used].min = max + 1;
+                offset->ranges[offset->used].max = *datasize - (max + 1);
+
+                offset->used++;
+
+            }
+
+        }
+        else
+        {
+            offset->ranges[offset->used].min = min;
+            offset->ranges[offset->used].max = max;
+
+            offset->used++;
+
+        }
+
+        offset->gen_ptr = offset->ranges;
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : offset = suivi de tolérances bornées à consulter.            *
+*                last   = dernière position validée.                          *
+*                pos    = nouvelle position potentielle.                      *
+*                                                                             *
+*  Description : Indique si une position est comprise dans un intervale.      *
+*                                                                             *
+*  Retour      : Bilan de la détermination.                                   *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+bool does_node_search_offset_include_pos_forward(const node_search_offset_t *offset, phys_t last, phys_t pos)
+{
+    bool result;                            /* Bilan à retourner           */
+    size_t i;                               /* Boucle de parcours          */
+    const node_offset_range_t *range;       /* Accès rapide aux infos.     */
+
+    result = false;
+
+    for (i = 0; i < offset->used; i++)
+    {
+        range = &offset->gen_ptr[i];
+
+        result = ((last + range->min) <= pos && pos <= (last + range->max));
+        if (result) break;
+
+    }
+
+    return result;
+
+}
diff --git a/src/analysis/scan/patterns/tokens/offset.h b/src/analysis/scan/patterns/tokens/offset.h
new file mode 100644
index 0000000..b458717
--- /dev/null
+++ b/src/analysis/scan/patterns/tokens/offset.h
@@ -0,0 +1,101 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * offset.h - prototypes pour la prise en compte des espaces entre octets dans un motif de recherche
+ *
+ * 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_TOKENS_OFFSET_H
+#define _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H
+
+
+#include <stdbool.h>
+
+#include "../../../../arch/vmpa.h"
+
+
+
+/* Mémorisation d'une souplesse dans les positions visées */
+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
+     * sont encore non initialisés.
+     *
+     * Ensuite ces bornes représentent bien un espace séparant les résultats
+     * issus de deux noeuds.
+     */
+    phys_t min;                             /* Position minimale           */
+    phys_t max;                             /* Position maximale           */
+
+} node_offset_range_t;
+
+
+/* Fournit les bornes d'une zone à analyser. */
+bool get_node_offset_range(const node_offset_range_t *, phys_t, phys_t, phys_t *, phys_t *);
+
+
+
+
+
+
+/* Mémorisation d'une souplesse dans les positions visées */
+typedef struct _node_search_offset_t
+{
+    node_offset_range_t range;              /* Bornes de décalage uniques  */
+
+    node_offset_range_t *ranges;            /* Bornes de décalage multiples*/
+    size_t allocated;                       /* Nombre d'allocations        */
+
+    node_offset_range_t *gen_ptr;           /* Accès générique à la liste  */
+
+    size_t used;                            /* Nombre de bornes présentes  */
+
+} node_search_offset_t;
+
+
+/* Initialise une mémorisation d'intervales de tolérance. */
+void init_node_search_offset(node_search_offset_t *);
+
+/* Copie une mémorisation d'intervales entre positions. */
+void copy_node_search_offset(node_search_offset_t *, const node_search_offset_t *);
+
+/* Fusionne une mémorisation d'intervales entre positions. */
+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 *);
+
+/* 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 *);
+
+/* 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 *);
+
+#define disable_all_ranges_in_node_search_offset(off) \
+    (off)->used = 0
+
+/* Indique si une position est comprise dans un intervale. */
+bool does_node_search_offset_include_pos_forward(const node_search_offset_t *, phys_t, phys_t);
+
+
+
+#endif  /* _ANALYSIS_SCAN_PATTERNS_TOKENS_OFFSET_H */
diff --git a/src/analysis/scan/patterns/tokens/plain-int.h b/src/analysis/scan/patterns/tokens/plain-int.h
index 40a71b5..5748160 100644
--- a/src/analysis/scan/patterns/tokens/plain-int.h
+++ b/src/analysis/scan/patterns/tokens/plain-int.h
@@ -38,14 +38,6 @@ struct _GScanPlainBytes
 {
     GStringToken parent;                    /* A laisser en premier        */
 
-    sized_binary_t orig;                    /* Motif d'origine avant modifs*/
-    GScanTokenModifier *modifier;           /* Transformateur pour le motif*/
-    ScanPlainBytesFlags flags;              /* Fanions associés au motif   */
-
-    sized_binary_t *raw;                    /* Liste de motifs à couvrir   */
-    tracked_scan_atom_t *atoms;             /* Atomes correspondants       */
-    size_t count;                           /* Taille de cette liste       */
-
 };
 
 /* Encadrement d'une recherche de texte brut (classe) */
@@ -57,7 +49,7 @@ struct _GScanPlainBytesClass
 
 
 /* Met en place un gestionnaire de recherche de texte brut. */
-bool g_scan_plain_bytes_create(GScanPlainBytes *, const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags);
+bool g_scan_plain_bytes_create(GScanPlainBytes *, GScanTokenNode *);
 
 
 
diff --git a/src/analysis/scan/patterns/tokens/plain.c b/src/analysis/scan/patterns/tokens/plain.c
index 26e7dfa..2eb6bbc 100644
--- a/src/analysis/scan/patterns/tokens/plain.c
+++ b/src/analysis/scan/patterns/tokens/plain.c
@@ -29,6 +29,7 @@
 
 
 #include "plain-int.h"
+#include "nodes/plain.h"
 
 
 
@@ -58,12 +59,6 @@ static void g_scan_plain_bytes_output_to_text(const GScanPlainBytes *, GScanCont
 /* Affiche un motif de recherche au format JSON. */
 static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *, GScanContext *, const sized_string_t *, unsigned int, int);
 
-/* Inscrit la définition d'un motif dans un moteur de recherche. */
-static bool g_scan_plain_bytes_enroll(GScanPlainBytes *, GScanContext *, GEngineBackend *, size_t);
-
-/* Transforme les correspondances locales en trouvailles. */
-static void g_scan_plain_bytes_check(const GScanPlainBytes *, GScanContext *, GBinContent *, pending_matches_t *);
-
 
 
 /* ---------------------------------------------------------------------------------- */
@@ -91,7 +86,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
 {
     GObjectClass *object;                   /* Autre version de la classe  */
     GSearchPatternClass *pattern;           /* Version de classe ancêtre   */
-    GStringTokenClass *token;               /* Version de classe parente   */
 
     object = G_OBJECT_CLASS(klass);
 
@@ -103,11 +97,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
     pattern->to_text = (output_pattern_to_text_fc)g_scan_plain_bytes_output_to_text;
     pattern->to_json = (output_pattern_to_json_fc)g_scan_plain_bytes_output_to_json;
 
-    token = G_STRING_TOKEN_CLASS(klass);
-
-    token->enroll = (enroll_token_fc)g_scan_plain_bytes_enroll;
-    token->check = (check_token_fc)g_scan_plain_bytes_check;
-
 }
 
 
@@ -125,13 +114,6 @@ static void g_scan_plain_bytes_class_init(GScanPlainBytesClass *klass)
 
 static void g_scan_plain_bytes_init(GScanPlainBytes *bytes)
 {
-    init_szstr(&bytes->orig);
-    bytes->modifier = NULL;
-    bytes->flags = SPBF_NONE;
-
-    bytes->raw = NULL;
-    bytes->atoms = NULL;
-    bytes->count = 0;
 
 }
 
@@ -150,8 +132,6 @@ static void g_scan_plain_bytes_init(GScanPlainBytes *bytes)
 
 static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes)
 {
-    g_clear_object(&bytes->modifier);
-
     G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->dispose(G_OBJECT(bytes));
 
 }
@@ -171,19 +151,6 @@ static void g_scan_plain_bytes_dispose(GScanPlainBytes *bytes)
 
 static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
 {
-    size_t i;                               /* Boucle de parcours          */
-
-    exit_szstr(&bytes->orig);
-
-    for (i = 0; i < bytes->count; i++)
-        exit_szstr(&bytes->raw[i]);
-
-    if (bytes->raw != NULL)
-        free(bytes->raw);
-
-    if (bytes->atoms != NULL)
-        free(bytes->atoms);
-
     G_OBJECT_CLASS(g_scan_plain_bytes_parent_class)->finalize(G_OBJECT(bytes));
 
 }
@@ -191,9 +158,7 @@ static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
 
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : text     = texte brut à rechercher.                          *
-*                modifier = transformateur éventuel à solliciter.             *
-*                flags    = particularités à prendre en considération.        *
+*  Paramètres  : root  = représentation du motif à recherche.                 *
 *                                                                             *
 *  Description : Construit un gestionnaire de recherche de texte brut.        *
 *                                                                             *
@@ -203,25 +168,24 @@ static void g_scan_plain_bytes_finalize(GScanPlainBytes *bytes)
 *                                                                             *
 ******************************************************************************/
 
-GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags)
+GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *root)
 {
     GSearchPattern *result;                 /* Structure à retourner       */
 
     result = g_object_new(G_TYPE_SCAN_PLAIN_BYTES, NULL);
 
-    if (!g_scan_plain_bytes_create(G_SCAN_PLAIN_BYTES(result), text, modifier, flags))
+    if (!g_scan_plain_bytes_create(G_SCAN_PLAIN_BYTES(result), root))
         g_clear_object(&result);
 
     return result;
 
 }
 
+
 /******************************************************************************
 *                                                                             *
-*  Paramètres  : bytes    = encadrement de motif à initialiser pleinement.    *
-*                text     = texte brut à rechercher.                          *
-*                modifier = transformateur éventuel à solliciter.             *
-*                flags    = particularités à prendre en considération.        *
+*  Paramètres  : bytes = encadrement de motif à initialiser pleinement.       *
+*                root  = représentation du motif à recherche.                 *
 *                                                                             *
 *  Description : Met en place un gestionnaire de recherche de texte brut.     *
 *                                                                             *
@@ -231,21 +195,19 @@ GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *text, GScanTokenMod
 *                                                                             *
 ******************************************************************************/
 
-bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, const sized_binary_t *text, GScanTokenModifier *modifier, ScanPlainBytesFlags flags)
+bool g_scan_plain_bytes_create(GScanPlainBytes *bytes, GScanTokenNode *root)
 {
     bool result;                            /* Bilan à retourner           */
+    ScanPlainNodeFlags flags;               /* Propriétés à interpréter    */
+    bool fullword;                          /* Cible de mots entiers ?     */
+    bool private;                           /* Vocation privée ?           */
 
-    result = true;
+    flags = g_scan_token_node_plain_get_flags(G_SCAN_TOKEN_NODE_PLAIN(root));
 
-    szstrdup(&bytes->orig, text);
+    fullword = (flags & SPNF_FULLWORD);
+    private = (flags & SPNF_PRIVATE);
 
-    if (modifier != NULL)
-    {
-        bytes->modifier = modifier;
-        g_object_ref(G_OBJECT(modifier));
-    }
-
-    bytes->flags = flags;
+    result = g_string_token_create(G_STRING_TOKEN(bytes), root, fullword, private);
 
     return result;
 
@@ -302,192 +264,3 @@ static void g_scan_plain_bytes_output_to_json(const GScanPlainBytes *pattern, GS
     /* TODO */
 
 }
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : bytes   = 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). *
-*                                                                             *
-*  Description : Inscrit la définition d'un motif dans un moteur de recherche.*
-*                                                                             *
-*  Retour      : Bilan de l'opération à renvoyer.                             *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static bool g_scan_plain_bytes_enroll(GScanPlainBytes *bytes, GScanContext *context, GEngineBackend *backend, size_t maxsize)
-{
-    return false;
-#if 0
-    bool result;                            /* Statut à retourner          */
-    size_t i;                               /* Boucle de parcours #1       */
-    tracked_scan_atom_t atom;               /* Atome identifié             */
-    size_t letters;                         /* Nombre de lettres présentes */
-    size_t k;                               /* Boucle de parcours #2       */
-    size_t extra_count;                     /* Quantité pour l'exhaustivité*/
-    sized_binary_t *extra;                  /* Couverture supplémntaire    */
-    size_t remaining;                       /* Quantité restant à traiter  */
-
-    /* Génération d'une base de chaînes à couvrir */
-
-    if (bytes->modifier == NULL)
-    {
-        bytes->raw = malloc(sizeof(sized_binary_t));
-        bytes->count = 1;
-
-        szstrdup(&bytes[0].raw[0], &bytes->orig);
-
-        result = true;
-
-    }
-    else
-        result = g_scan_token_modifier_transform(bytes->modifier, &bytes->orig, &bytes->raw, &bytes->count);
-
-    if (!result)
-        goto exit;
-
-    /* Préparation pour la mémorisation des atomes */
-
-    bytes->atoms = malloc(bytes->count * sizeof(tracked_scan_atom_t));
-
-    /* Recherche des atomes */
-
-    for (i = 0; i < bytes->count; i++)
-    {
-        if (bytes->flags & SPBF_CASE_INSENSITIVE)
-        {
-            find_best_atom(&bytes->raw[i], maxsize, &atom, &letters);
-
-            if (letters == 0)
-                bytes->atoms[i] = atom;
-
-            /* Insertion des combinaisons pour couvrir toutes les casses */
-            else
-            {
-                for (k = 0, extra_count = 1; k < letters; k++, extra_count *= 2)
-                    ;
-
-                extra = make_atoms_case_insensitive(&bytes->raw[i], extra_count);
-
-                remaining = bytes->count - i - 1;
-
-                bytes->count += (extra_count - 1);
-
-                bytes->raw = realloc(bytes->raw, bytes->count * sizeof(sized_binary_t));
-
-                memmove(&bytes->raw[i + extra_count], &bytes->raw[i + 1], remaining * sizeof(sized_binary_t));
-
-                for (k = 0; k < extra_count; k++)
-                    bytes->raw[i + k] = extra[k];
-
-                free(extra);
-
-                bytes->atoms = realloc(bytes->raw, bytes->count * sizeof(tracked_scan_atom_t));
-
-                for (k = 0; k < extra_count; k++)
-                    bytes->atoms[i + k] = atom;
-
-                i += extra_count - 1;
-
-            }
-
-        }
-
-        else
-            find_best_atom(&bytes->raw[i], maxsize, &bytes->atoms[i], &letters);
-
-    }
-
-    /* Enregistrements en masse */
-
-
-    for (i = 0; i < bytes->count && result; i++)
-        result = enroll_prepared_atom(&bytes->raw[i], context, backend, &bytes->atoms[i]);
-
- exit:
-
-    return result;
-#endif
-}
-
-
-/******************************************************************************
-*                                                                             *
-*  Paramètres  : bytes   = 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.       *
-*                                                                             *
-*  Retour      : -                                                            *
-*                                                                             *
-*  Remarques   : -                                                            *
-*                                                                             *
-******************************************************************************/
-
-static void g_scan_plain_bytes_check(const GScanPlainBytes *bytes, GScanContext *context, GBinContent *content, pending_matches_t *matches)
-{
-#if 0
-
-    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 start;                           /* Point de départ             */
-    vmpa2t pos;                             /* Position dans les données   */
-    const bin_t *ptr;                       /* Accès aux données brutes    */
-    int ret;                                /* Bilan d'une comparaison     */
-
-    for (i = 0; i < bytes->count; i++)
-    {
-        raw = &bytes->raw[i];
-        atom = &bytes->atoms[i];
-
-        found = g_scan_context_get_atom_matches(context, atom->pid, &count);
-
-        for (k = 0; k < count; k++)
-        {
-            start = found[k] - atom->pos;
-
-            init_vmpa(&pos, start, VMPA_NO_VIRTUAL);
-
-            /* Validation du contenu avant l'atome */
-
-            if (atom->pos > 0)
-            {
-                ptr = g_binary_content_get_raw_access(content, &pos, atom->pos);
-
-                ret = memcmp(raw->data, ptr, atom->pos);
-                if (ret != 0) continue;
-
-            }
-
-            /* 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);
-
-                ret = memcmp(raw->data + atom->pos + atom->len, ptr, atom->rem);
-                if (ret != 0) continue;
-
-            }
-
-            /* Mémorisation de la correspondance */
-
-            add_pending_matches(matches, start, raw->len);
-
-        }
-
-    }
-#endif
-}
diff --git a/src/analysis/scan/patterns/tokens/plain.h b/src/analysis/scan/patterns/tokens/plain.h
index 80a0b4d..6ff48d7 100644
--- a/src/analysis/scan/patterns/tokens/plain.h
+++ b/src/analysis/scan/patterns/tokens/plain.h
@@ -28,9 +28,8 @@
 #include <glib-object.h>
 
 
-#include "../modifier.h"
+#include "node.h"
 #include "../../pattern.h"
-#include "../../../../common/szstr.h"
 
 
 
@@ -49,21 +48,11 @@ typedef struct _GScanPlainBytes GScanPlainBytes;
 typedef struct _GScanPlainBytesClass GScanPlainBytesClass;
 
 
-/* Propriétés d'un élément textuel à rechercher */
-typedef enum _ScanPlainBytesFlags
-{
-    SPBF_NONE             = 0x0,            /* Aucune particularité        */
-    SPBF_CASE_INSENSITIVE = 0x1,            /* Ignorance de la casse       */
-    SPBF_FULL_WORD        = 0x2,            /* Recherche de mot entier     */
-
-} ScanPlainBytesFlags;
-
-
 /* Indique le type défini pour une suite d'octets à retrouver dans un binaire. */
 GType g_scan_plain_bytes_get_type(void);
 
 /* Construit un gestionnaire de recherche de texte brut. */
-GSearchPattern *g_scan_plain_bytes_new(const sized_binary_t *, GScanTokenModifier *, ScanPlainBytesFlags);
+GSearchPattern *g_scan_plain_bytes_new(GScanTokenNode *);
 
 
 
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
index 4727c9d..1d68b80 100644
--- a/src/analysis/scan/rule.c
+++ b/src/analysis/scan/rule.c
@@ -369,6 +369,8 @@ 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       */
     GSearchPattern *pattern;                /* Motif à intégrer            */
@@ -378,11 +380,14 @@ void g_scan_rule_check(GScanRule *rule, GEngineBackend *backend, GScanContext *c
 
     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 */
 
     for (i = 0; i < rule->bytes_used; i++)
     {
-        init_pending_matches(&matches);
+        init_pending_matches(&matches, &start.physical, &end.physical);
 
         pattern = rule->bytes_locals[i];
 
diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l
index 18594c4..594d4d9 100644
--- a/src/analysis/scan/tokens.l
+++ b/src/analysis/scan/tokens.l
@@ -32,7 +32,7 @@
 *                                                                             *
 ******************************************************************************/
 
-static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out)
+static void rost_unescape_string_bytes(const char *src, size_t len, sized_string_t *out)
 {
     size_t i;                               /* Boucle de parcours          */
     bin_t byte;                             /* Octet à analyser            */
@@ -52,30 +52,177 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
 
                 switch (next)
                 {
-                    case '\a':
+                    case 'a':
+                        out->data[out->len++] = '\a';
+                        break;
+
+                    case 'b':
+                        out->data[out->len++] = '\b';
+                        break;
+
+                    case 't':
+                        out->data[out->len++] = '\t';
+                        break;
+
+                    case 'n':
+                        out->data[out->len++] = '\n';
+                        break;
+
+                    case 'v':
+                        out->data[out->len++] = '\v';
+                        break;
+
+                    case 'f':
+                        out->data[out->len++] = '\f';
+                        break;
+
+                    case 'r':
+                        out->data[out->len++] = '\r';
+                        break;
+
+                    case 'e':
+                        out->data[out->len++] = '\e';
+                        break;
+
+                    case '"':
+                        out->data[out->len++] = '\"';
+                        break;
+
+                    case '\\':
                         out->data[out->len++] = '\\';
                         break;
 
-                    case '\t':
+                    case 'x':
+
+                        next = src[i + 2];
+
+                        switch (next)
+                        {
+                            case '0' ... '9':
+                                out->data[out->len] = (next - '0');
+                                break;
+
+                            case 'A' ... 'F':
+                                out->data[out->len] = 0xa + (next - 'A');
+                                break;
+
+                            case 'a' ... 'f':
+                                out->data[out->len] = 0xa + (next - 'a');
+                                break;
+
+                        }
+
+                        out->data[out->len] <<= 4;
+
+                        next = src[i + 3];
+
+                        switch (next)
+                        {
+                            case '0' ... '9':
+                                out->data[out->len] |= (next - '0');
+                                break;
+
+                            case 'A' ... 'F':
+                                out->data[out->len] |= 0xa + (next - 'A');
+                                break;
+
+                            case 'a' ... 'f':
+                                out->data[out->len] |= 0xa + (next - 'a');
+                                break;
+
+                        }
+
+                        out->len++;
+
+                        i += 2;
+                        break;
+
+                }
+
+                i++;
+                break;
+
+            default:
+                out->data[out->len++] = byte;
+                break;
+
+        }
+
+    }
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : src = liste d'octets à traiter.                              *
+*                len = taille de cette liste.                                 *
+*                out = série d'octets bruts obtenue. [OUT]                    *
+*                                                                             *
+*  Description : Transcrit une série d'octets en en remplaçant certains.      *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out)
+{
+    size_t i;                               /* Boucle de parcours          */
+    bin_t byte;                             /* Octet à analyser            */
+    bin_t next;                             /* Octet suivant               */
+
+    out->len = 0;
+
+    for (i = 0; i < len; i++)
+    {
+        byte = src[i];
+
+        switch (byte)
+        {
+            case '\\':
+
+                next = src[i + 1];
+
+                switch (next)
+                {
+                    case 'a':
+                        out->data[out->len++] = '\a';
+                        break;
+
+                    case 'b':
+                        out->data[out->len++] = '\b';
+                        break;
+
+                    case 't':
                         out->data[out->len++] = '\t';
                         break;
 
-                    case '\n':
+                    case 'n':
                         out->data[out->len++] = '\n';
                         break;
 
-                    case '\v':
+                    case 'v':
                         out->data[out->len++] = '\v';
                         break;
 
-                    case '\f':
+                    case 'f':
                         out->data[out->len++] = '\f';
                         break;
 
-                    case '\r':
+                    case 'r':
                         out->data[out->len++] = '\r';
                         break;
 
+                    case 'e':
+                        out->data[out->len++] = '\e';
+                        break;
+
+                    case '"':
+                        out->data[out->len++] = '\"';
+                        break;
+
                     case '\\':
                         out->data[out->len++] = '\\';
                         break;
@@ -91,11 +238,11 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
                                 break;
 
                             case 'A' ... 'F':
-                                out->data[out->len] = 0x10 + (next - 'A');
+                                out->data[out->len] = 0xa + (next - 'A');
                                 break;
 
                             case 'a' ... 'f':
-                                out->data[out->len] = 0x10 + (next - 'a');
+                                out->data[out->len] = 0xa + (next - 'a');
                                 break;
 
                         }
@@ -111,11 +258,11 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
                                 break;
 
                             case 'A' ... 'F':
-                                out->data[out->len] |= 0x10 + (next - 'A');
+                                out->data[out->len] |= 0xa + (next - 'A');
                                 break;
 
                             case 'a' ... 'f':
-                                out->data[out->len] |= 0x10 + (next - 'a');
+                                out->data[out->len] |= 0xa + (next - 'a');
                                 break;
 
                         }
@@ -175,7 +322,7 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
 %option yylineno
 %option never-interactive
 
-%x include_path
+%x inc_path
 
 %x rule_intro
 %x raw_block
@@ -200,8 +347,12 @@ static void rost_unescape_bytes(const char *src, size_t len, sized_string_t *out
 %x comment
 
 
+str_not_escaped [^\"\\]
+str_escaped \\a|\\b|\\t|\\n|\\v|\\f|\\r|\\e|\\\"|\\\\|\\x{hbyte}
+str_mixed ({str_not_escaped}|{str_escaped})
 
 hbyte [0-9a-fA-F]{2}
+mbyte (\?[0-9a-fA-F]|[0-9a-fA-F]\?)
 
 reg_allowed [^^$.|/{}()\[\]*+?\\]
 reg_allowed_escaped \\^|\\$|\\\.|\\\||\\\/|\\\{|\\\}|\\\(|\\\)|\\\[|\\\]|\\\*|\\\+|\\\?|\\\\
@@ -219,15 +370,35 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
 %%
 
 
+"include"                           { PUSH_STATE(inc_path); return INCLUDE; }
 
+<inc_path>\"{str_not_escaped}+\"    {
+                                        POP_STATE;
 
-"include"                       { PUSH_STATE(include_path); return INCLUDE; }
+                                        yylval->sized_cstring.data = yytext + 1;
+                                        yylval->sized_cstring.len = yyleng - 2;
+
+                                        return PLAIN_TEXT;
+                                    }
+
+<inc_path>\"{str_mixed}+\"          {
+                                        POP_STATE;
+
+                                        rost_unescape_string_bytes(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+                                        /* Pour rendre plus lisibles les impressions de débogage */
+                                        tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+                                        yylval->tmp_cstring = tmp_0;
+
+                                        return ESCAPED_TEXT;
+                                    }
+
+
+%{ /* Définition locale d'une règle */ %}
 
-<include_path>"\""              {
-                                    POP_STATE;
-                                    *used = 0;
-                                    PUSH_STATE(strlit);
-                                }
 
 "rule"                          { PUSH_STATE(rule_intro); return RAW_RULE; }
 
@@ -295,6 +466,41 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
                                 }
 
 
+%{ /* Définitions communes pour la section "bytes:" */ %}
+
+<strings>"fullword"                 { return FULLWORD; }
+<strings>"nocase"                   { return NOCASE; }
+<strings>"private"                  { return PRIVATE; }
+
+<strings>"="                        { PUSH_STATE(bytes_value); return ASSIGN; }
+
+
+%{ /* Définition de motif en texte brut */ %}
+
+<bytes_value>\"{str_not_escaped}+\" {
+                                        POP_STATE;
+
+                                        yylval->sized_cstring.data = yytext + 1;
+                                        yylval->sized_cstring.len = yyleng - 2;
+
+                                        return PLAIN_TEXT;
+                                    }
+
+<bytes_value>\"{str_mixed}+\"       {
+                                        POP_STATE;
+
+                                        rost_unescape_string_bytes(yytext + 1, yyleng - 2, tmp_0);
+
+#ifndef NDEBUG
+                                        /* Pour rendre plus lisibles les impressions de débogage */
+                                        tmp_0->data[tmp_0->len] = '\0';
+#endif
+
+                                        yylval->tmp_cstring = tmp_0;
+
+                                        return ESCAPED_TEXT;
+                                    }
+
 
 %{ /* Définition de motif en hexadécimal */ %}
 
@@ -350,26 +556,21 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
                                                     break;
 
                                                 case 'A' ... 'F':
-                                                    value = 0x10 + (byte - 'A');
+                                                    value = 0xa + (byte - 'A');
                                                     break;
 
                                                 case 'a' ... 'f':
-                                                    value = 0x10 + (byte - 'a');
+                                                    value = 0xa + (byte - 'a');
                                                     break;
 
                                             }
 
                                             if (even)
-                                            {
                                                 tmp_0->data[tmp_0->len] = (value << 4);
-                                                even = false;
-                                            }
-
                                             else
-                                            {
                                                 tmp_0->data[tmp_0->len++] |= value;
-                                                even = true;
-                                            }
+
+                                            even = !even;
 
                                         }
 
@@ -402,6 +603,73 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
 
                                     }
 
+   <bytes_hex>{mbyte}([ ]*{mbyte})* {
+                                        bool even;
+                                        size_t i;
+                                        bin_t byte;
+                                        bin_t value;
+
+                                        tmp_0->len = 0;
+                                        tmp_1->len = 0;
+
+                                        even = true;
+
+                                        for (i = 0; i < yyleng; i++)
+                                        {
+                                            byte = yytext[i];
+
+                                            switch (byte)
+                                            {
+                                                case ' ':
+                                                    continue;
+                                                    break;
+
+                                                case '?':
+                                                    even = !even;
+                                                    continue;
+                                                    break;
+
+                                                case '0' ... '9':
+                                                    value = (byte - '0');
+                                                    break;
+
+                                                case 'A' ... 'F':
+                                                    value = 0xa + (byte - 'A');
+                                                    break;
+
+                                                case 'a' ... 'f':
+                                                    value = 0xa + (byte - 'a');
+                                                    break;
+
+                                            }
+
+                                            if (even)
+                                            {
+                                                tmp_0->data[tmp_0->len++] = (value << 4);
+                                                tmp_1->data[tmp_1->len++] = 0xf0;
+                                            }
+                                            else
+                                            {
+                                                tmp_0->data[tmp_0->len++] = value;
+                                                tmp_1->data[tmp_1->len++] = 0x0f;
+                                            }
+
+                                            even = !even;
+
+                                        }
+
+#ifndef NDEBUG
+                                        /* Pour rendre plus lisibles les impressions de débogage */
+                                        tmp_0->data[tmp_0->len] = '\0';
+                                        tmp_1->data[tmp_1->len] = '\0';
+#endif
+
+                                        yylval->masked.tmp_values = tmp_0;
+                                        yylval->masked.tmp_masks = tmp_1;
+                                        return SEMI_MASK;
+
+                                    }
+
 
 %{ /* Définition d'expressions régulières */ %}
 
@@ -573,16 +841,6 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
                                     return NAME;
                                 }
 
-<strings>"="                    { PUSH_STATE(bytes_value); return ASSIGN; }
-
-
-<bytes_value>\"[^\"\\]+\"            {
-                                    POP_STATE;
-                                    yylval->sized_cstring.data = yytext + 1;
-                                    yylval->sized_cstring.len = yyleng - 2;
-                                    return PLAIN_STRING;
-                                }
-
 
 
 
@@ -592,7 +850,7 @@ bytes_id [A-Za-z_][A-Za-z0-9_]*
                                     PUSH_STATE(bytes_value_raw);
                                 }
 
-<bytes_value_raw>"\""                { POP_STATE; /*yylval->pattern = *built_pattern*/; return MASKED_STRING; }
+<bytes_value_raw>"\""                { POP_STATE; /*yylval->pattern = *built_pattern*/; return 11111/*MASKED_STRING*/; }
 
 <bytes_value_raw>"\\\""              { }//g_bytes_pattern_append_data(*built_pattern, '"', 0xff); }
 <bytes_value_raw>"\\t"               { }//g_bytes_pattern_append_data(*built_pattern, '\t', 0xff); }
diff --git a/src/common/szstr.h b/src/common/szstr.h
index 0091482..aad1920 100644
--- a/src/common/szstr.h
+++ b/src/common/szstr.h
@@ -37,7 +37,11 @@
 /* Structure associant une chaîne et sa taille */
 typedef struct _sized_string_t
 {
-    char *data;                         /* Chaîne de caractères        */
+    union {
+        const char *static_data;        /* Données non modifiées       */
+        char *data;                     /* Chaîne de caractères        */
+    };
+
     size_t len;                         /* Taille correspondante       */
 
 } sized_string_t;
diff --git a/tests/analysis/scan/functions.py b/tests/analysis/scan/functions.py
index 8553018..96f029f 100644
--- a/tests/analysis/scan/functions.py
+++ b/tests/analysis/scan/functions.py
@@ -76,6 +76,64 @@ rule test {
             self.check_rule_success(rule, cnt)
 
 
+    def testMathOperations(self):
+        """Perform math operations with core functions."""
+
+        rule = '''
+rule test {
+
+   condition:
+      math.to_string(123) == "123"
+         and math.to_string(291, 16) == "0x123"
+         and math.to_string(-83, 8) == "-0123"
+         and math.to_string(123, 2) == "0b1111011"
+
+}
+'''
+
+        self.check_rule_success(rule)
+
+
+    def testStringOperations(self):
+        """Perform string operations with core functions."""
+
+        rule = '''
+rule test {
+
+   condition:
+      string.lower("ABCd") == "abcd" and string.lower("123abc") == "123abc"
+
+}
+'''
+
+        self.check_rule_success(rule)
+
+        rule = '''
+rule test {
+
+   condition:
+      string.upper("abcD") == "ABCD" and string.upper("123ABC") == "123ABC"
+
+}
+'''
+
+        self.check_rule_success(rule)
+
+        rule = '''
+rule test {
+
+   condition:
+      string.to_int("123") == 123
+         and string.to_int("123", 16) == 291
+         and string.to_int("0x123") == 291
+         and string.to_int("-0123") == -83
+
+}
+'''
+
+        self.check_rule_success(rule)
+
+
     def testTime(self):
         """Check current time."""
 
diff --git a/tests/analysis/scan/pyapi.py b/tests/analysis/scan/pyapi.py
index b5b2453..4b066f3 100644
--- a/tests/analysis/scan/pyapi.py
+++ b/tests/analysis/scan/pyapi.py
@@ -6,7 +6,6 @@ from gi._constants import TYPE_INVALID
 from pychrysalide.analysis.scan import ScanExpression
 from pychrysalide.analysis.scan import ScanOptions
 from pychrysalide.analysis.scan import find_token_modifiers_for_name
-from pychrysalide.analysis.scan.patterns.modifiers import PlainModifier
 from pychrysalide.glibext import ComparableItem
 
 
diff --git a/tests/analysis/scan/scanning_hex.py b/tests/analysis/scan/scanning_hex.py
index e009b79..32979c8 100644
--- a/tests/analysis/scan/scanning_hex.py
+++ b/tests/analysis/scan/scanning_hex.py
@@ -3,8 +3,218 @@ from common import RostTestClass
 from pychrysalide.analysis.contents import MemoryContent
 
 
-class TestRostScanning(RostTestClass):
-    """TestCases for the bytes section syntax."""
+class TestRostScanningBinary(RostTestClass):
+    """TestCases for the bytes section syntax (binary)."""
+
+    def testLonelyPatterns(self):
+        """Evaluate the most simple patterns."""
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 41 }
+
+   condition:
+      #a == 1 and @a[0] == 0
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 62 }
+
+   condition:
+      #a == 1 and @a[0] == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 66 }
+
+   condition:
+      #a == 1 and @a[0] == 5
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?1 }
+
+   condition:
+      #a == 1 and @a[0] == 0
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?2 }
+
+   condition:
+      #a == 1 and @a[0] == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?6 }
+
+   condition:
+      #a == 1 and @a[0] == 5
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testLonelyPatternsNot(self):
+        """Evaluate the most simple patterns (not version)."""
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ~41 }
+
+   condition:
+      #a == 5 and @a[0] == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ~62 }
+
+   condition:
+      #a == 5 and @a[0] == 0
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ~66 }
+
+   condition:
+      #a == 5 and @a[4] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ~?1 }
+
+   condition:
+      #a == 5 and @a[0] == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ~?2 }
+
+   condition:
+      #a == 5 and @a[0] == 0
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'Abcdef')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ~?6 }
+
+   condition:
+      #a == 5 and @a[4] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
 
     def testSimpleHexPattern(self):
         """Test a simple hex pattern."""
@@ -24,3 +234,480 @@ rule test {
 '''
 
         self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 2d 41 62 63 }
+
+   condition:
+      #a == 1 and @a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testSimpleMaskedHexPattern(self):
+        """Test a simple masked hex pattern."""
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?1 6? ?3 }
+
+   condition:
+      #a == 1 and @a[0] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testHexPatternWithPlainAndMasked(self):
+        """Test hex patterns with plain and masked bytes."""
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 41 6? ?3 }
+
+   condition:
+      #a == 1 and @a[0] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 4? 62 ?3 }
+
+   condition:
+      #a == 1 and @a[0] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 4? ?2 63 }
+
+   condition:
+      #a == 1 and @a[0] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 4? ?2 ?3 }
+
+   condition:
+      #a == 1 and @a[0] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 2d 4? ?2 63 }
+
+   condition:
+      #a == 1 and @a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 2d 4? 62 ?3 2d }
+
+   condition:
+      #a == 1 and @a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 2? 41 6? 63 ?d }
+
+   condition:
+      #a == 1 and @a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testHexPatternWithPlainAndHoles(self):
+        """Test hex patterns with plain bytes and holes."""
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 33 ?? 41 ?? 63 ?? 34 }
+
+   condition:
+      #a == 1 and @a[0] == 2
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?? 33 ?? 41 ?? 63 ?? 34 ?? }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?? 33 [1-5] 63 ?? 34 ?? }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { [3-4] 41 ?? 63 ?? 34 ?? }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?? 33 ?? 41 ?? 63 [3-] }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testHexPatternWithMaskedAndHoles(self):
+        """Test hex patterns with masked bytes and holes."""
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?3 ?? 4? ?? 6? ?? ?4 }
+
+   condition:
+      #a == 1 and @a[0] == 2
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?? ?3 ?? 4? ?? 6? ?? ?4 ?? }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?? ?3 [1-5] ?3 ?? ?4 ?? }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { [3-4] ?1 ?? ?3 ?? ?4 ?? }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ?? 3? ?? 4? ?? 6? [3-] }
+
+   condition:
+      #a == 1 and @a[0] == 1 and !a[0] == 9
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testPipedPlainHexPatterns(self):
+        """Look for several patterns at once with piped definition."""
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 41 62 ( 63 | 64 | 65 ) }
+
+   condition:
+      #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ( 41 | f2 | f3 ) 62 63 }
+
+   condition:
+      #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 41 ( 61 | 62 | 63 ) 63 }
+
+   condition:
+      #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ( 41 62 63 | 42 62 63 | 43 62 63 ) }
+
+   condition:
+      #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testPipedMaskedHexPatterns(self):
+        """Look for several patterns at once with piped definition."""
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 4? 6? ( ?3 | ?4 | ?5 ) }
+
+   condition:
+      #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ( ?1 | ?2 | ?3 ) 6? 6? }
+
+   condition:
+      console.log("COUNTER: ", #a) and #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { 4? ( ?1 | ?2 | ?3 ) 6? }
+
+   condition:
+      #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = { ( 4? ?2 ?3 | 4? 6? 6? | ?3 6? ?3 ) }
+
+   condition:
+      #a == 1 and @a[0] == 4 and !a[0] == 3
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
diff --git a/tests/analysis/scan/scanning_str.py b/tests/analysis/scan/scanning_str.py
new file mode 100644
index 0000000..ff36ca3
--- /dev/null
+++ b/tests/analysis/scan/scanning_str.py
@@ -0,0 +1,194 @@
+
+from common import RostTestClass
+from pychrysalide.analysis.contents import MemoryContent
+
+
+class TestRostScanningStrings(RostTestClass):
+    """TestCases for the bytes section syntax (strings)."""
+
+    def testSimpleStringPattern(self):
+        """Test a simple string pattern."""
+
+        cnt = MemoryContent(b'123-Abc-456')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "Abc"
+
+   condition:
+      #a == 1 and @a[0] == 4
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testEscapedStringPattern(self):
+        """Test escaped string patterns."""
+
+        cnt = MemoryContent(b'\a\b\t\n\v\f\r' + bytes([ 0x1b ]) + b'"\\\xff')
+
+        rule = r'''
+rule test {
+
+   strings:
+      $a = "\a\b\t\n\v\f\r\e\"\\\xff"
+
+   condition:
+      #a == 1 and @a[0] == 0
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'\a\b\t\n--123--\v\f\r' + bytes([ 0x1b ]) + b'"\\\xff')
+
+        rule = r'''
+rule test {
+
+   strings:
+      $a = "\a\b\t\n--123--\v\f\r\e\"\\\xff"
+
+   condition:
+      #a == 1 and @a[0] == 0
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testStringModifiers(self):
+        """Check string modifiers output."""
+
+        cnt = MemoryContent(b'--414243--')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "ABC" hex
+
+   condition:
+      #a == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'--ABC--')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "ABC" plain
+
+   condition:
+      #a == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'--CBA--')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "ABC" rev
+
+   condition:
+      #a == 1
+
+}
+'''
+
+
+    def testStringPatternFullword(self):
+        """Test a fullword string pattern."""
+
+        cnt = MemoryContent(b'ABCDEF 123 ')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "DEF" fullword
+      $b = "123" fullword
+
+   condition:
+      #a == 0 and #b == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'DEF 123 ')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "DEF" fullword
+      $b = "123" fullword
+
+   condition:
+      #a == 1 and #b == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+        cnt = MemoryContent(b'\tDEF 123 ')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "DEF" fullword
+      $b = "123" fullword
+
+   condition:
+      #a == 1 and #b == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
+
+
+    def testStringPatternCase(self):
+        """Test a string pattern with case care."""
+
+        cnt = MemoryContent(b'abc123-Abc123Def456GHI...z0z1z2z3z4z5z6z7z8z9')
+
+        rule = '''
+rule test {
+
+   strings:
+      $a = "Abc" nocase
+      $b = "ABC123DEF456GHI" nocase
+      $z = "z0z1z2z3z4z5z6z7z8z9" nocase
+
+   condition:
+      #a == 2 and #b == 1 and #z == 1
+
+}
+'''
+
+        self.check_rule_success(rule, content=cnt)
-- 
cgit v0.11.2-87-g4458