summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/pychrysalide/analysis/scan/scanner.c125
-rw-r--r--src/analysis/scan/matches/bytes.c55
-rw-r--r--src/analysis/scan/pattern.c128
-rw-r--r--src/analysis/scan/pattern.h4
-rw-r--r--src/analysis/scan/rule.c128
-rw-r--r--src/analysis/scan/rule.h4
-rw-r--r--src/analysis/scan/scanner.c128
-rw-r--r--src/analysis/scan/scanner.h4
8 files changed, 550 insertions, 26 deletions
diff --git a/plugins/pychrysalide/analysis/scan/scanner.c b/plugins/pychrysalide/analysis/scan/scanner.c
index befbc80..e2d5a18 100644
--- a/plugins/pychrysalide/analysis/scan/scanner.c
+++ b/plugins/pychrysalide/analysis/scan/scanner.c
@@ -25,6 +25,7 @@
#include "scanner.h"
+#include <malloc.h>
#include <pygobject.h>
@@ -34,6 +35,7 @@
#include <analysis/scan/scanner-int.h>
+#include "context.h"
#include "options.h"
#include "../content.h"
#include "../../access.h"
@@ -49,6 +51,12 @@ static int py_content_scanner_init(PyObject *, PyObject *, PyObject *);
/* Lance une analyse d'un contenu binaire. */
static PyObject *py_content_scanner_analyze(PyObject *, PyObject *);
+/* Convertit un gestionnaire de recherches en JSON. */
+static PyObject *py_content_scanner_convert_to_json(PyObject *, PyObject *);
+
+/* Indique le chemin d'un éventuel fichier de source. */
+static PyObject *py_content_scanner_get_filename(PyObject *, void *);
+
/******************************************************************************
@@ -188,6 +196,121 @@ static PyObject *py_content_scanner_analyze(PyObject *self, PyObject *args)
/******************************************************************************
* *
+* Paramètres : self = classe représentant un format. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Convertit un gestionnaire de recherches en texte. *
+* *
+* Retour : Données textuelles ou None en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_content_scanner_convert_to_text(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Contexte de suivi à renvoyer*/
+ GScanContext *context; /* Contexte d'analyse */
+ int ret; /* Bilan de lecture des args. */
+ GContentScanner *scanner; /* Encadrement de recherche */
+ char *out; /* Données en sortie */
+
+#define CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD PYTHON_METHOD_DEF \
+( \
+ convert_to_text, "$self, context, /", \
+ METH_VARARGS, py_content_scanner, \
+ "Output a scan results as text.\n" \
+ "\n" \
+ "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \
+ " instance provided by a previous call to *self.analyze()*. This" \
+ " context stores all the scan results.\n" \
+ "\n" \
+ "The method returns a string value, or *None* in case of failure." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context);
+ if (!ret) return NULL;
+
+ scanner = G_CONTENT_SCANNER(pygobject_get(self));
+
+ out = g_content_scanner_convert_to_text(scanner, context);
+
+ if (out != NULL)
+ {
+ result = PyUnicode_FromString(out);
+ free(out);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
+* Paramètres : self = classe représentant un format. *
+* args = arguments fournis à l'appel. *
+* *
+* Description : Convertit un gestionnaire de recherches en JSON. *
+* *
+* Retour : Données textuelles au format JSON ou None en cas d'erreur. *
+* *
+* Remarques : - *
+* *
+******************************************************************************/
+
+static PyObject *py_content_scanner_convert_to_json(PyObject *self, PyObject *args)
+{
+ PyObject *result; /* Contexte de suivi à renvoyer*/
+ GScanContext *context; /* Contexte d'analyse */
+ int ret; /* Bilan de lecture des args. */
+ GContentScanner *scanner; /* Encadrement de recherche */
+ char *out; /* Données en sortie */
+
+#define CONTENT_SCANNER_CONVERT_TO_JSON_METHOD PYTHON_METHOD_DEF \
+( \
+ convert_to_json, "$self, context, /", \
+ METH_VARARGS, py_content_scanner, \
+ "Output a scan results as JSON data.\n" \
+ "\n" \
+ "The *context* argument is a pychrysalide.analysis.scan.ScanContext" \
+ " instance provided by a previous call to *self.analyze()*. This" \
+ " context stores all the scan results.\n" \
+ "\n" \
+ "The method returns JSON data as a string value, or *None* in case" \
+ " of failure." \
+)
+
+ ret = PyArg_ParseTuple(args, "O&", convert_to_scan_context, &context);
+ if (!ret) return NULL;
+
+ scanner = G_CONTENT_SCANNER(pygobject_get(self));
+
+ out = g_content_scanner_convert_to_json(scanner, context);
+
+ if (out != NULL)
+ {
+ result = PyUnicode_FromString(out);
+ free(out);
+ }
+ else
+ {
+ result = Py_None;
+ Py_INCREF(result);
+ }
+
+ return result;
+
+}
+
+
+/******************************************************************************
+* *
* Paramètres : self = objet Python concerné par l'appel. *
* closure = non utilisé ici. *
* *
@@ -247,6 +370,8 @@ PyTypeObject *get_python_content_scanner_type(void)
{
static PyMethodDef py_content_scanner_methods[] = {
CONTENT_SCANNER_ANALYZE_METHOD,
+ CONTENT_SCANNER_CONVERT_TO_TEXT_METHOD,
+ CONTENT_SCANNER_CONVERT_TO_JSON_METHOD,
{ NULL }
};
diff --git a/src/analysis/scan/matches/bytes.c b/src/analysis/scan/matches/bytes.c
index 043170e..ccd73a1 100644
--- a/src/analysis/scan/matches/bytes.c
+++ b/src/analysis/scan/matches/bytes.c
@@ -449,7 +449,7 @@ static void g_scan_bytes_match_output_to_json(const GScanBytesMatch *match, cons
write(fd, ",\n", 2);
- /* Affichage du contenu */
+ /* Affichage du contenu brut */
for (i = 0; i < level; i++)
write(fd, padding->data, padding->len);
@@ -462,12 +462,61 @@ static void g_scan_bytes_match_output_to_json(const GScanBytesMatch *match, cons
for (k = 0; k < match->len; k++)
{
- if (isprint(data[k]))
+ if (data[k] == '\\')
+ write(fd, "\\\\", 2);
+
+ else if (isprint(data[k]))
write(fd, &data[k], 1);
else
{
- write(fd, "\\x", 2);
+ write(fd, "\\u", 2);
+
+ /**
+ * Cf. https://datatracker.ietf.org/doc/html/rfc8259#section-7
+ */
+ ret = snprintf(value, ULLONG_MAXLEN, "%04hhx", data[k]);
+
+ if (ret > 0)
+ {
+ assert(ret == 4);
+ write(fd, value, ret);
+ }
+
+ else
+ {
+ log_simple_message(LMT_EXT_ERROR, "Error while converting data!");
+ write(fd, "??", 2);
+ }
+
+ }
+
+ }
+
+ write(fd, "\",\n", 3);
+
+ /* Affichage du contenu en version humainement lisible */
+
+ for (i = 0; i < level; i++)
+ write(fd, padding->data, padding->len);
+
+ write(fd, "\"content_str\": \"", 16);
+
+ init_vmpa(&pos, match->start, VMPA_NO_VIRTUAL);
+
+ data = g_binary_content_get_raw_access(match->content, &pos, match->len);
+
+ for (k = 0; k < match->len; k++)
+ {
+ if (data[k] == '\\')
+ write(fd, "\\\\", 2);
+
+ else if (isprint(data[k]))
+ write(fd, &data[k], 1);
+
+ else
+ {
+ write(fd, "\\\\x", 3);
ret = snprintf(value, ULLONG_MAXLEN, "%02hhx", data[k]);
diff --git a/src/analysis/scan/pattern.c b/src/analysis/scan/pattern.c
index 5b966d2..797f4ac 100644
--- a/src/analysis/scan/pattern.c
+++ b/src/analysis/scan/pattern.c
@@ -25,10 +25,15 @@
#include <malloc.h>
+#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
#include "pattern-int.h"
+#include "../../core/logs.h"
@@ -216,14 +221,69 @@ void g_search_pattern_output_to_text(const GSearchPattern *pattern, GScanContext
* *
* Description : Convertit un motif de recherche en texte. *
* *
-* Retour : - *
+* Retour : Données textuelles ou NULL en cas d'erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_search_pattern_convert_as_text(const GSearchPattern *pattern, GScanContext *context)
+char *g_search_pattern_convert_as_text(const GSearchPattern *pattern, GScanContext *context)
{
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-pattern2text-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ g_search_pattern_output_to_text(pattern, context, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
}
@@ -294,14 +354,72 @@ void g_search_pattern_output_to_json(const GSearchPattern *pattern, GScanContext
* *
* Description : Convertit un motif de recherche en JSON. *
* *
-* Retour : - *
+* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_search_pattern_convert_as_json(const GSearchPattern *pattern, GScanContext *context)
+char *g_search_pattern_convert_as_json(const GSearchPattern *pattern, GScanContext *context)
{
- /* TODO */
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-pattern2json-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ padding.data = " ";
+ padding.len = 3;
+
+ g_search_pattern_output_to_json(pattern, context, &padding, 0, fd, false);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
}
diff --git a/src/analysis/scan/pattern.h b/src/analysis/scan/pattern.h
index 0e4327d..72f87e4 100644
--- a/src/analysis/scan/pattern.h
+++ b/src/analysis/scan/pattern.h
@@ -66,13 +66,13 @@ void g_search_pattern_set_name(GSearchPattern *, const char *, size_t);
void g_search_pattern_output_to_text(const GSearchPattern *, GScanContext *, int);
/* Convertit un motif de recherche en texte. */
-void g_search_pattern_convert_as_text(const GSearchPattern *, GScanContext *);
+char *g_search_pattern_convert_as_text(const GSearchPattern *, GScanContext *);
/* Affiche un motif de recherche au format JSON. */
void g_search_pattern_output_to_json(const GSearchPattern *, GScanContext *, const sized_string_t *, unsigned int, int, bool);
/* Convertit un motif de recherche en JSON. */
-void g_search_pattern_convert_as_json(const GSearchPattern *, GScanContext *);
+char *g_search_pattern_convert_as_json(const GSearchPattern *, GScanContext *);
diff --git a/src/analysis/scan/rule.c b/src/analysis/scan/rule.c
index 4ef1e3c..a1fcfcb 100644
--- a/src/analysis/scan/rule.c
+++ b/src/analysis/scan/rule.c
@@ -26,7 +26,11 @@
#include <assert.h>
#include <regex.h>
+#include <stdio.h>
#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
#include "rule-int.h"
@@ -561,15 +565,69 @@ void g_scan_rule_output_to_text(const GScanRule *rule, GScanContext *context, bo
* *
* Description : Convertit une règle en texte. *
* *
-* Retour : - *
+* Retour : Données textuelles ou NULL en cas d'erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_scan_rule_convert_as_text(const GScanRule *rule, GScanContext *context)
+char *g_scan_rule_convert_as_text(const GScanRule *rule, GScanContext *context)
{
- /* TODO */
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-rule2text-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ g_scan_rule_output_to_text(rule, context, true, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
}
@@ -668,14 +726,72 @@ void g_scan_rule_output_to_json(const GScanRule *rule, GScanContext *context, co
* *
* Description : Convertit une règle en JSON. *
* *
-* Retour : - *
+* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_scan_rule_convert_as_json(const GScanRule *rule, GScanContext *context)
+char *g_scan_rule_convert_as_json(const GScanRule *rule, GScanContext *context)
{
- /* TODO */
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-rule2json-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ padding.data = " ";
+ padding.len = 3;
+
+ g_scan_rule_output_to_json(rule, context, &padding, 0, fd, false);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
}
diff --git a/src/analysis/scan/rule.h b/src/analysis/scan/rule.h
index 7ade51b..6ab5105 100644
--- a/src/analysis/scan/rule.h
+++ b/src/analysis/scan/rule.h
@@ -84,13 +84,13 @@ void g_scan_rule_check(GScanRule *, GEngineBackend *, GScanContext *);
void g_scan_rule_output_to_text(const GScanRule *, GScanContext *, bool, int);
/* Convertit une règle en texte. */
-void g_scan_rule_convert_as_text(const GScanRule *, GScanContext *);
+char *g_scan_rule_convert_as_text(const GScanRule *, GScanContext *);
/* Affiche une règle au format JSON. */
void g_scan_rule_output_to_json(const GScanRule *, GScanContext *, const sized_string_t *, unsigned int, int, bool);
/* Convertit une règle en JSON. */
-void g_scan_rule_convert_as_json(const GScanRule *, GScanContext *);
+char *g_scan_rule_convert_as_json(const GScanRule *, GScanContext *);
diff --git a/src/analysis/scan/scanner.c b/src/analysis/scan/scanner.c
index 29f47eb..41fa0de 100644
--- a/src/analysis/scan/scanner.c
+++ b/src/analysis/scan/scanner.c
@@ -27,6 +27,10 @@
#include <assert.h>
#include <libgen.h>
#include <malloc.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
#include "decl.h"
@@ -556,15 +560,69 @@ void g_content_scanner_output_to_text(const GContentScanner *scanner, GScanConte
* *
* Description : Convertit un gestionnaire de recherches en texte. *
* *
-* Retour : - *
+* Retour : Données textuelles ou NULL en cas d'erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_content_scanner_convert_as_text(const GContentScanner *scanner, GScanContext *context)
+char *g_content_scanner_convert_to_text(const GContentScanner *scanner, GScanContext *context)
{
- /* TODO */
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-scanner2text-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ g_content_scanner_output_to_text(scanner, context, true, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
}
@@ -624,14 +682,72 @@ void g_content_scanner_output_to_json(const GContentScanner *scanner, GScanConte
* *
* Description : Convertit un gestionnaire de recherches en JSON. *
* *
-* Retour : - *
+* Retour : Données textuelles au format JSON ou NULL en cas d'erreur. *
* *
* Remarques : - *
* *
******************************************************************************/
-void g_content_scanner_convert_as_json(const GContentScanner *scanner, GScanContext *context)
+char *g_content_scanner_convert_to_json(const GContentScanner *scanner, GScanContext *context)
{
- /* TODO */
+ char *result; /* Données à retourner */
+ char *name; /* Nom "unique" pour le canal */
+ int ret; /* Bilan de création de nom */
+ int fd; /* Canal d'écriture */
+ sized_string_t padding; /* Bourrage pour le JSON */
+ struct stat info; /* Infos. incluant une taille */
+ ssize_t got; /* Données effectivement relues*/
+
+ static unsigned long long counter = 0;
+
+ result = NULL;
+
+ ret = asprintf(&name, "rost-scanner2json-%llu", counter++);
+ if (ret == -1) goto exit;
+
+ fd = memfd_create(name, MFD_CLOEXEC);
+ if (fd == -1)
+ {
+ LOG_ERROR_N("memfd_create");
+ goto exit_with_name;
+ }
+
+ padding.data = " ";
+ padding.len = 3;
+
+ g_content_scanner_output_to_json(scanner, context, &padding, 0, fd);
+
+ ret = fstat(fd, &info);
+ if (ret != 0)
+ {
+ LOG_ERROR_N("fstat");
+ goto exit_with_name_and_fd;
+ }
+
+ result = malloc((info.st_size + 1) * sizeof(char));
+
+ lseek(fd, SEEK_SET, 0);
+
+ got = read(fd, result, info.st_size);
+ if (got != info.st_size)
+ {
+ LOG_ERROR_N("read");
+ free(result);
+ goto exit_with_name_and_fd;
+ }
+
+ result[info.st_size] = '\0';
+
+ exit_with_name_and_fd:
+
+ close(fd);
+
+ exit_with_name:
+
+ free(name);
+
+ exit:
+
+ return result;
}
diff --git a/src/analysis/scan/scanner.h b/src/analysis/scan/scanner.h
index d2b5dc1..e03ecda 100644
--- a/src/analysis/scan/scanner.h
+++ b/src/analysis/scan/scanner.h
@@ -76,13 +76,13 @@ GScanContext *g_content_scanner_analyze(GContentScanner *, GScanOptions *, GBinC
void g_content_scanner_output_to_text(const GContentScanner *, GScanContext *, bool, int);
/* Convertit un gestionnaire de recherches en texte. */
-void g_content_scanner_convert_as_text(const GContentScanner *, GScanContext *);
+char *g_content_scanner_convert_to_text(const GContentScanner *, GScanContext *);
/* Affiche un gestionnaire de recherches au format JSON. */
void g_content_scanner_output_to_json(const GContentScanner *, GScanContext *, const sized_string_t *, unsigned int, int);
/* Convertit un gestionnaire de recherches en JSON. */
-void g_content_scanner_convert_as_json(const GContentScanner *, GScanContext *);
+char *g_content_scanner_convert_to_json(const GContentScanner *, GScanContext *);