From 062984a6a4b726dd9060aa1354cf557d942654d9 Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 13 Oct 2023 04:40:01 +0200
Subject: Pipe pattern modifiers when requested.

---
 plugins/apihashing/classics/ror13.c              |   2 +-
 src/analysis/scan/grammar.y                      |  40 ++-
 src/analysis/scan/patterns/modifiers/Makefile.am |   2 +
 src/analysis/scan/patterns/modifiers/list.c      |   4 +-
 src/analysis/scan/patterns/modifiers/pipe-int.h  |  54 +++
 src/analysis/scan/patterns/modifiers/pipe.c      | 405 +++++++++++++++++++++++
 src/analysis/scan/patterns/modifiers/pipe.h      |  68 ++++
 src/analysis/scan/tokens.l                       |   4 +
 8 files changed, 571 insertions(+), 8 deletions(-)
 create mode 100644 src/analysis/scan/patterns/modifiers/pipe-int.h
 create mode 100644 src/analysis/scan/patterns/modifiers/pipe.c
 create mode 100644 src/analysis/scan/patterns/modifiers/pipe.h

diff --git a/plugins/apihashing/classics/ror13.c b/plugins/apihashing/classics/ror13.c
index 1b2421d..5bae60b 100644
--- a/plugins/apihashing/classics/ror13.c
+++ b/plugins/apihashing/classics/ror13.c
@@ -274,7 +274,7 @@ static bool g_scan_ror13_modifier_transform(const GScanRor13Modifier *modifier,
 
     binary = &(*dest)[0];
 
-    for (i = 0; i < scount && result; i++)
+    for (i = 0; i < scount; i++, binary++)
     {
         _src = src + i;
 
diff --git a/src/analysis/scan/grammar.y b/src/analysis/scan/grammar.y
index 36f6df9..1daa519 100644
--- a/src/analysis/scan/grammar.y
+++ b/src/analysis/scan/grammar.y
@@ -44,6 +44,7 @@ typedef void *yyscan_t;
 #include "patterns/customizer.h"
 #include "patterns/modifier.h"
 #include "patterns/modifiers/list.h"
+#include "patterns/modifiers/pipe.h"
 #include "patterns/tokens/hex.h"
 #include "patterns/tokens/plain.h"
 #include "patterns/tokens/nodes/any.h"
@@ -211,6 +212,9 @@ YY_DECL;
 %token DOT              "."
 %token PIPE             "|"
 
+%token MOD_GROUP_O      "(("
+%token MOD_GROUP_C      "))"
+
 %token NONE             "none"
 %token ANY              "any"
 %token ALL              "all"
@@ -255,7 +259,7 @@ YY_DECL;
 
 %type <modifier> modifiers
 %type <modifier> _modifiers
-%type <modifier> chained_modifiers
+                                                                                                                                                                   //%type <modifier> chained_modifiers
 %type <modifier> mod_stage
 %type <modifier> modifier
 %type <modifier> modifier_args
@@ -509,7 +513,9 @@ YY_DECL;
                    {
                        $$ = $1;
 
+
                        // if (...) useless
+                       // ex : xxx | { yyy zzz }
 
                    }
                    ;
@@ -518,19 +524,43 @@ YY_DECL;
                    {
                        $$ = $1;
                    }
-                   | "(" chained_modifiers ")"
+                   |  _modifiers "|" mod_stage
                    {
-                       $$ = $2;
+                       bool status;
+
+                       if (G_IS_SCAN_MODIFIER_PIPE($1))
+                           $$ = $1;
+                       else
+                       {
+                           $$ = g_scan_modifier_pipe_new();
+                           g_scan_modifier_pipe_add(G_SCAN_MODIFIER_PIPE($$), $1);
+                       }
+
+                       g_scan_modifier_pipe_add(G_SCAN_MODIFIER_PIPE($$), $3);
+
                    }
                    ;
 
- chained_modifiers : _modifiers "|" _modifiers
+/*
+ chained_modifiers : modifiers "|" modifiers
+                   {
+                       printf("need chains....\n");
+
+                       $$ = NULL;
+
+                   }
                    ;
+*/
 
          mod_stage : modifier
                    {
                        $$ = $1;
                    }
+                   | "((" _modifiers "))"
+                   {
+                       $$ = NULL;
+                       YYERROR; /* TODO */
+                   }
                    | mod_stage modifier
                    {
                        bool status;
@@ -562,7 +592,7 @@ YY_DECL;
                            char *_msg;
                            int _ret;
 
-                           _ret = asprintf(&_msg, _("Unknown modifier: \"%s\""), $1.data);
+                           _ret = asprintf(&_msg, _("Unknown modifier: \"%.*s\""), (int)$1.len, $1.data);
 
                            if (_ret != -1)
                            {
diff --git a/src/analysis/scan/patterns/modifiers/Makefile.am b/src/analysis/scan/patterns/modifiers/Makefile.am
index 900e4e4..da046b9 100644
--- a/src/analysis/scan/patterns/modifiers/Makefile.am
+++ b/src/analysis/scan/patterns/modifiers/Makefile.am
@@ -7,6 +7,8 @@ libanalysisscanpatternsmodifiers_la_SOURCES = \
 	list-int.h								\
 	list.h list.c							\
 	lower.h lower.c							\
+	pipe-int.h								\
+	pipe.h pipe.c							\
 	plain.h plain.c							\
 	rev.h rev.c								\
 	upper.h upper.c							\
diff --git a/src/analysis/scan/patterns/modifiers/list.c b/src/analysis/scan/patterns/modifiers/list.c
index 040d2f8..285b89d 100644
--- a/src/analysis/scan/patterns/modifiers/list.c
+++ b/src/analysis/scan/patterns/modifiers/list.c
@@ -378,11 +378,11 @@ static bool g_scan_modifier_list_transform(const GScanModifierList *modifier, co
         result = g_scan_token_modifier_transform(modifier->modifiers[i], src, scount, &extra, &extra_count);
         if (!result) goto exit;
 
-        new = (*dest) + *dcount;
-
         *dcount += extra_count;
         *dest = realloc(*dest, *dcount * sizeof(sized_binary_t));
 
+        new = (*dest) + *dcount - extra_count;
+
         for (k = 0; k < extra_count; k++, new++)
             copy_szstr(*new, extra[k]);
 
diff --git a/src/analysis/scan/patterns/modifiers/pipe-int.h b/src/analysis/scan/patterns/modifiers/pipe-int.h
new file mode 100644
index 0000000..63c4d97
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/pipe-int.h
@@ -0,0 +1,54 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pipe-int.h - prototypes internes pour la gestion de combinaisons de transformateurs
+ *
+ * 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_MODIFIERS_PIPE_INT_H
+#define _ANALYSIS_SCAN_MODIFIERS_PIPE_INT_H
+
+
+#include "pipe.h"
+
+
+#include "../modifier-int.h"
+
+
+
+/* Enchainement combinatoire de transformations d'octets (instance) */
+struct _GScanModifierPipe
+{
+    GScanTokenModifier parent;              /* A laisser en premier        */
+
+    GScanTokenModifier **modifiers;         /* Pipee de transformateurs    */
+    size_t count;                           /* Taille de cette pipee       */
+
+};
+
+/* Enchainement combinatoire de transformations d'octets (classe) */
+struct _GScanModifierPipeClass
+{
+    GScanTokenModifierClass parent;         /* A laisser en premier        */
+
+};
+
+
+
+#endif  /* _ANALYSIS_SCAN_MODIFIERS_PIPE_INT_H */
diff --git a/src/analysis/scan/patterns/modifiers/pipe.c b/src/analysis/scan/patterns/modifiers/pipe.c
new file mode 100644
index 0000000..7c659ea
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/pipe.c
@@ -0,0 +1,405 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pipe.c - gestion de combinaisons de transformateurs
+ *
+ * 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 "pipe.h"
+
+
+#include <assert.h>
+#include <malloc.h>
+
+
+#include "pipe-int.h"
+
+
+
+/* ----------------------- RECHERCHE D'UN MOTIF DE TEXTE BRUT ----------------------- */
+
+
+/* Initialise la classe des pipee de transformations d'octets. */
+static void g_scan_modifier_pipe_class_init(GScanModifierPipeClass *);
+
+/* Initialise une instance de pipee de transformations d'octets. */
+static void g_scan_modifier_pipe_init(GScanModifierPipe *);
+
+/* Supprime toutes les références externes. */
+static void g_scan_modifier_pipe_dispose(GScanModifierPipe *);
+
+/* Procède à la libération totale de la mémoire. */
+static void g_scan_modifier_pipe_finalize(GScanModifierPipe *);
+
+
+
+/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */
+
+
+/* Fournit le nom d'appel d'un modificateur pour motif. */
+static char *g_scan_modifier_pipe_get_name(const GScanModifierPipe *);
+
+/* Transforme une séquence d'octets pour motif de recherche. */
+static bool g_scan_modifier_pipe_transform(const GScanModifierPipe *, const sized_binary_t *, size_t, sized_binary_t **, size_t *);
+
+/* Retrouve l'origine d'une correspondance à partir d'un indice. */
+static char *g_scan_modifier_pipe_get_path(const GScanModifierPipe *, size_t *);
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                         RECHERCHE D'UN MOTIF DE TEXTE BRUT                         */
+/* ---------------------------------------------------------------------------------- */
+
+
+/* Indique le type défini pour une série de transformations d'octets. */
+G_DEFINE_TYPE(GScanModifierPipe, g_scan_modifier_pipe, G_TYPE_SCAN_TOKEN_MODIFIER);
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : klass = classe à initialiser.                                *
+*                                                                             *
+*  Description : Initialise la classe des pipee de transformations d'octets.  *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_class_init(GScanModifierPipeClass *klass)
+{
+    GObjectClass *object;                   /* Autre version de la classe  */
+    GScanTokenModifierClass *modifier;      /* Version de classe parente   */
+
+    object = G_OBJECT_CLASS(klass);
+
+    object->dispose = (GObjectFinalizeFunc/* ! */)g_scan_modifier_pipe_dispose;
+    object->finalize = (GObjectFinalizeFunc)g_scan_modifier_pipe_finalize;
+
+    modifier = G_SCAN_TOKEN_MODIFIER_CLASS(klass);
+
+    modifier->get_name = (get_scan_modifier_name_fc)g_scan_modifier_pipe_get_name;
+
+    modifier->transform = (transform_scan_token_fc)g_scan_modifier_pipe_transform;
+    modifier->get_path = (get_modifier_path)g_scan_modifier_pipe_get_path;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pipe = instance à initialiser.                               *
+*                                                                             *
+*  Description : Initialise une instance de pipee de transformations d'octets.*
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_init(GScanModifierPipe *pipe)
+{
+    pipe->modifiers = NULL;
+    pipe->count = 0;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pipe = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Supprime toutes les références externes.                     *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_dispose(GScanModifierPipe *pipe)
+{
+    size_t i;                               /* Boucle de parcours          */
+
+    for (i = 0; i < pipe->count; i++)
+        g_clear_object(&pipe->modifiers[i]);
+
+    G_OBJECT_CLASS(g_scan_modifier_pipe_parent_class)->dispose(G_OBJECT(pipe));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pipe = instance d'objet GLib à traiter.                      *
+*                                                                             *
+*  Description : Procède à la libération totale de la mémoire.                *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static void g_scan_modifier_pipe_finalize(GScanModifierPipe *pipe)
+{
+    if (pipe->modifiers != NULL)
+        free(pipe->modifiers);
+
+    G_OBJECT_CLASS(g_scan_modifier_pipe_parent_class)->finalize(G_OBJECT(pipe));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : -                                                            *
+*                                                                             *
+*  Description : Construit une pipee de modificateurs d'octets.               *
+*                                                                             *
+*  Retour      : Mécanisme mis en place.                                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_modifier_pipe_new(void)
+{
+    GScanTokenModifier *result;                    /* Structure à retourner       */
+
+    result = g_object_new(G_TYPE_SCAN_MODIFIER_PIPE, NULL);
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pipe     = pipee de modificateurs à étendre.                 *
+*                modifier = modificateur à intégrer.                          *
+*                                                                             *
+*  Description : Intègre un nouveau transformateur à enchaîner.               *
+*                                                                             *
+*  Retour      : -                                                            *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+void g_scan_modifier_pipe_add(GScanModifierPipe *pipe, GScanTokenModifier *modifier)
+{
+    pipe->modifiers = realloc(pipe->modifiers, ++pipe->count * sizeof(GScanTokenModifier *));
+
+    pipe->modifiers[pipe->count - 1] = modifier;
+    g_object_ref(G_OBJECT(modifier));
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pipe = série à consulter.                                    *
+*                                                                             *
+*  Description : Indique le nombre de transformateurs intégrés dans la série. *
+*                                                                             *
+*  Retour      : Nombre de modificateurs représentés.                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+size_t g_scan_modifier_pipe_count(const GScanModifierPipe *pipe)
+{
+    size_t result;                          /* Quantité à retourner        */
+
+    result = pipe->count;
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : pipe  = série à consulter.                                   *
+*                index = indice du paramètre à retourner.                     *
+*                                                                             *
+*  Description : Fournit un transformateur donné de la série.                 *
+*                                                                             *
+*  Retour      : Modificateur inclus dans la pipee ou NULL si mauvais indice. *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+GScanTokenModifier *g_scan_modifier_pipe_get(const GScanModifierPipe *pipe, size_t index)
+{
+    GScanTokenModifier *result;             /* Instance à retourner        */
+
+    assert(index < pipe->count);
+
+    if (index < pipe->count)
+    {
+        result = pipe->modifiers[index];
+        g_object_ref(G_OBJECT(result));
+    }
+
+    else
+        result = NULL;
+
+    return result;
+
+}
+
+
+
+/* ---------------------------------------------------------------------------------- */
+/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
+/* ---------------------------------------------------------------------------------- */
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à consulter.                         *
+*                                                                             *
+*  Description : Fournit le nom d'appel d'un modificateur pour motif.         *
+*                                                                             *
+*  Retour      : Désignation humaine.                                         *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_modifier_pipe_get_name(const GScanModifierPipe *modifier)
+{
+    char *result;                           /* Désignation à retourner     */
+
+    result = strdup("(pipe)");
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à solliciter.                        *
+*                src      = séquences d'octets à traiter.                     *
+*                scount   = quantité de ces séquences.                        *
+*                dest     = nouvelle(s) séquence(s) d'octets obtenue(s) [OUT] *
+*                dcount   = quantité de ces séquences.                        *
+*                                                                             *
+*  Description : Transforme une séquence d'octets pour motif de recherche.    *
+*                                                                             *
+*  Retour      : Bilan de l'opération : succès ou échec.                      *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static bool g_scan_modifier_pipe_transform(const GScanModifierPipe *modifier, const sized_binary_t *src, size_t scount, sized_binary_t **dest, size_t *dcount)
+{
+    bool result;                            /* Bilan d'opération à renvoyer*/
+    size_t i;                               /* Boucle de parcours #1       */
+    sized_binary_t *tmp_in;                 /* Motifs supplémentaires      */
+    size_t tmp_in_count;                    /* Quantité de ces motifs      */
+    sized_binary_t *tmp_out;                /* Motifs supplémentaires      */
+    size_t tmp_out_count;                   /* Quantité de ces motifs      */
+    size_t k;                               /* Boucle de parcours #2       */
+
+    for (i = 0; i < modifier->count; i++)
+    {
+        if (i == 0)
+            result = g_scan_token_modifier_transform(modifier->modifiers[i],
+                                                     src, scount, &tmp_out, &tmp_out_count);
+
+        else
+        {
+            tmp_in = tmp_out;
+            tmp_in_count = tmp_out_count;
+
+            result = g_scan_token_modifier_transform(modifier->modifiers[i],
+                                                     tmp_in, tmp_in_count, &tmp_out, &tmp_out_count);
+
+            for (k = 0; k < tmp_in_count; k++)
+                exit_szstr(&tmp_in[k]);
+
+            if (tmp_in != NULL)
+                free(tmp_in);
+
+        }
+
+        if (!result)
+            break;
+
+    }
+
+    if (!result)
+    {
+        for (k = 0; k < tmp_out_count; k++)
+            exit_szstr(&tmp_out[k]);
+
+        if (tmp_out != NULL)
+            free(tmp_out);
+
+        *dest = NULL;
+        *dcount = 0;
+
+    }
+    else
+    {
+        *dcount += tmp_out_count;
+        *dest = tmp_out;
+    }
+
+    return result;
+
+}
+
+
+/******************************************************************************
+*                                                                             *
+*  Paramètres  : modifier = modificateur à consulter.                         *
+*                index    = indice de la combinaison ciblée. [OUT]            *
+*                                                                             *
+*  Description : Retrouve l'origine d'une correspondance à partir d'un indice.*
+*                                                                             *
+*  Retour      : Version humainement lisible de la combinaison.               *
+*                                                                             *
+*  Remarques   : -                                                            *
+*                                                                             *
+******************************************************************************/
+
+static char *g_scan_modifier_pipe_get_path(const GScanModifierPipe *modifier, size_t *index)
+{
+    char *result;                           /* Combinaison à retourner     */
+    size_t i;                               /* Boucle de parcours #1       */
+
+    result = NULL;
+
+    for (i = 0; i < modifier->count && result == NULL; i++)
+        result = g_scan_token_modifier_get_path(modifier->modifiers[i], index);
+
+    return result;
+
+}
diff --git a/src/analysis/scan/patterns/modifiers/pipe.h b/src/analysis/scan/patterns/modifiers/pipe.h
new file mode 100644
index 0000000..8f9ca48
--- /dev/null
+++ b/src/analysis/scan/patterns/modifiers/pipe.h
@@ -0,0 +1,68 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * pipe.h - prototypes pour la gestion de combinaisons de transformateurs
+ *
+ * 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_MODIFIERS_PIPE_H
+#define _ANALYSIS_SCAN_MODIFIERS_PIPE_H
+
+
+#include <glib-object.h>
+#include <stdbool.h>
+
+
+#include "../modifier.h"
+
+
+
+#define G_TYPE_SCAN_MODIFIER_PIPE            g_scan_modifier_pipe_get_type()
+#define G_SCAN_MODIFIER_PIPE(obj)            (G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_SCAN_MODIFIER_PIPE, GScanModifierPipe))
+#define G_IS_SCAN_MODIFIER_PIPE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE((obj), G_TYPE_SCAN_MODIFIER_PIPE))
+#define G_SCAN_MODIFIER_PIPE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST((klass), G_TYPE_SCAN_MODIFIER_PIPE, GScanModifierPipeClass))
+#define G_IS_SCAN_MODIFIER_PIPE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), G_TYPE_SCAN_MODIFIER_PIPE))
+#define G_SCAN_MODIFIER_PIPE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_SCAN_MODIFIER_PIPE, GScanModifierPipeClass))
+
+
+/* Enchainement combinatoire de transformations d'octets (instance) */
+typedef struct _GScanModifierPipe GScanModifierPipe;
+
+/* Enchainement combinatoire de transformations d'octets (classe) */
+typedef struct _GScanModifierPipeClass GScanModifierPipeClass;
+
+
+/* Indique le type défini pour une série de transformations d'octets. */
+GType g_scan_modifier_pipe_get_type(void);
+
+/* Construit une pipee de modificateurs d'octets. */
+GScanTokenModifier *g_scan_modifier_pipe_new(void);
+
+/* Intègre un nouveau transformateur à enchaîner. */
+void g_scan_modifier_pipe_add(GScanModifierPipe *, GScanTokenModifier *);
+
+/* Indique le nombre de transformateurs intégrés dans la série. */
+size_t g_scan_modifier_pipe_count(const GScanModifierPipe *);
+
+/* Fournit un transformateur donné de la pipee. */
+GScanTokenModifier *g_scan_modifier_pipe_get(const GScanModifierPipe *, size_t);
+
+
+
+#endif  /* _ANALYSIS_SCAN_MODIFIERS_PIPE_H */
diff --git a/src/analysis/scan/tokens.l b/src/analysis/scan/tokens.l
index 6633975..d81874a 100644
--- a/src/analysis/scan/tokens.l
+++ b/src/analysis/scan/tokens.l
@@ -615,6 +615,10 @@ bytes_fuzzy_id [\*A-Za-z_][\*A-Za-z0-9_]*
                                 }
 
 
+                        <bytes>"((" { return MOD_GROUP_O; }
+
+                        <bytes>"))" { return MOD_GROUP_C; }
+
                          <bytes>"(" { return PAREN_O; }
 
                          <bytes>")" { return PAREN_C; }
-- 
cgit v0.11.2-87-g4458