From 113f37b954e395beb2a335e5e364746c70af625d Mon Sep 17 00:00:00 2001
From: Cyrille Bagard <nocbos@gmail.com>
Date: Fri, 1 Feb 2019 19:12:31 +0100
Subject: Inserted an option to render disassembly even in batch mode.

---
 plugins/pychrysalide/analysis/loaded.c  | 30 ++++++++----
 plugins/pychrysalide/analysis/project.c | 19 +++++---
 src/analysis/binary.c                   |  7 +--
 src/analysis/loaded-int.h               |  2 +-
 src/analysis/loaded.c                   | 20 +++++---
 src/analysis/loaded.h                   |  4 +-
 src/analysis/project.c                  | 37 +++++++++------
 src/analysis/project.h                  |  4 +-
 src/gui/editor.c                        |  2 +-
 src/gui/menus/file.c                    |  2 +-
 src/gui/menus/project.c                 |  2 +-
 src/gui/panels/welcome.c                |  2 +-
 src/main.c                              |  6 +--
 tests/analysis/Makefile                 | 10 ++++
 tests/analysis/hm.c                     | 20 ++++++++
 tests/analysis/project.py               | 81 +++++++++++++++++++++++++++++++++
 16 files changed, 197 insertions(+), 51 deletions(-)
 create mode 100644 tests/analysis/Makefile
 create mode 100644 tests/analysis/hm.c
 create mode 100644 tests/analysis/project.py

diff --git a/plugins/pychrysalide/analysis/loaded.c b/plugins/pychrysalide/analysis/loaded.c
index 9c30261..37d11b4 100644
--- a/plugins/pychrysalide/analysis/loaded.c
+++ b/plugins/pychrysalide/analysis/loaded.c
@@ -61,7 +61,7 @@ static PyObject *py_loaded_content_get_content(PyObject *, void *);
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self = contenu binaire à manipuler.                          *
-*                args = non utilisé ici.                                      *
+*                args = arguments fournis à l'appel.                          *
 *                                                                             *
 *  Description : Lance l'analyse propre à l'élément chargé.                   *
 *                                                                             *
@@ -73,11 +73,18 @@ static PyObject *py_loaded_content_get_content(PyObject *, void *);
 
 static PyObject *py_loaded_content_analyze(PyObject *self, PyObject *args)
 {
+    int cache;                              /* Préparation de rendu ?      */
+    int ret;                                /* Bilan de lecture des args.  */
     GLoadedContent *content;                /* Version GLib de l'élément   */
 
+    cache = 0;
+
+    ret = PyArg_ParseTuple(args, "|p", &cache);
+    if (!ret) return NULL;
+
     content = G_LOADED_CONTENT(pygobject_get(self));
 
-    g_loaded_content_analyze(content);
+    g_loaded_content_analyze(content, cache);
 
     Py_RETURN_NONE;
 
@@ -87,7 +94,7 @@ static PyObject *py_loaded_content_analyze(PyObject *self, PyObject *args)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : self = contenu binaire à manipuler.                          *
-*                args = non utilisé ici.                                      *
+*                args = arguments fournis à l'appel.                          *
 *                                                                             *
 *  Description : Lance l'analyse de l'élément chargé et attend sa conclusion. *
 *                                                                             *
@@ -100,15 +107,22 @@ static PyObject *py_loaded_content_analyze(PyObject *self, PyObject *args)
 static PyObject *py_loaded_content_analyze_and_wait(PyObject *self, PyObject *args)
 {
     PyObject *result;                       /* Bilan à retourner           */
+    int cache;                              /* Préparation de rendu ?      */
+    int ret;                                /* Bilan de lecture des args.  */
     PyThreadState *_save;                   /* Sauvegarde de contexte      */
     GLoadedContent *content;                /* Version GLib de l'élément   */
     bool status;                            /* Bilan de l'opération        */
 
+    cache = 0;
+
+    ret = PyArg_ParseTuple(args, "|p", &cache);
+    if (!ret) return NULL;
+
     content = G_LOADED_CONTENT(pygobject_get(self));
 
     Py_UNBLOCK_THREADS;
 
-    status = g_loaded_content_analyze_and_wait(content);
+    status = g_loaded_content_analyze_and_wait(content, cache);
 
     Py_BLOCK_THREADS;
 
@@ -245,14 +259,14 @@ PyTypeObject *get_python_loaded_content_type(void)
     static PyMethodDef py_loaded_content_methods[] = {
         {
             "analyze", py_loaded_content_analyze,
-            METH_NOARGS,
-            "analyze($self, /)\n--\n\nStart the analysis of the loaded binary and " \
+            METH_VARARGS,
+            "analyze($self, cache, /)\n--\n\nStart the analysis of the loaded binary and " \
             "send an \"analyzed\" signal when done."
         },
         {
             "analyze_and_wait", py_loaded_content_analyze_and_wait,
-            METH_NOARGS,
-            "analyze_and_wait($self, /)\n--\n\nRun the analysis of the loaded binary and " \
+            METH_VARARGS,
+            "analyze_and_wait($self, cache, /)\n--\n\nRun the analysis of the loaded binary and " \
             "wait for its completion."
         },
         {
diff --git a/plugins/pychrysalide/analysis/project.c b/plugins/pychrysalide/analysis/project.c
index 137efbf..9046bf3 100644
--- a/plugins/pychrysalide/analysis/project.c
+++ b/plugins/pychrysalide/analysis/project.c
@@ -77,16 +77,18 @@ static PyObject *py_study_project_new(PyTypeObject *type, PyObject *args, PyObje
 {
     PyObject *result;                       /* Instance à retourner        */
     const char *filename;                   /* Destination de la sauvegarde*/
+    int cache;                              /* Préparation de rendu ?      */
     int ret;                                /* Bilan de lecture des args.  */
     GStudyProject *project;                 /* Version GLib du projet      */
 
     filename = NULL;
+    cache = 0;
 
-    ret = PyArg_ParseTuple(args, "|s", &filename);
+    ret = PyArg_ParseTuple(args, "|sp", &filename, &cache);
     if (!ret) return NULL;
 
     if (filename != NULL)
-        project = g_study_project_open(filename);
+        project = g_study_project_open(filename, cache);
     else
         project = g_study_project_new();
 
@@ -202,15 +204,18 @@ static bool filter_loadable_content_with_python(GLoadedContent *content, PyObjec
 
 static PyObject *py_study_project_discover_binary_content(PyObject *self, PyObject *args)
 {
-    PyObject *callable;                     /* Filtre de contenus éventuel */
     GBinContent *content;                   /* Instance de contenu binaire */
+    int cache;                              /* Préparation de rendu ?      */
+    PyObject *callable;                     /* Filtre de contenus éventuel */
     int ret;                                /* Bilan de lecture des args.  */
     GStudyProject *project;                 /* Version GLib du format      */
 
+    cache = 0;
     callable = NULL;
 
-    ret = PyArg_ParseTuple(args, "O&|O&",
+    ret = PyArg_ParseTuple(args, "O&|pO&",
                            convert_to_binary_content, &content,
+                           &cache,
                            convert_to_callable, &callable);
     if (!ret) return NULL;
 
@@ -220,14 +225,14 @@ static PyObject *py_study_project_discover_binary_content(PyObject *self, PyObje
     {
         Py_INCREF(callable);
 
-        g_study_project_discover_binary_content(project, content,
+        g_study_project_discover_binary_content(project, content, cache,
                                                 (filter_loadable_cb)filter_loadable_content_with_python,
                                                 callable);
 
     }
 
     else
-        g_study_project_discover_binary_content(project, content, NULL, NULL);
+        g_study_project_discover_binary_content(project, content, cache, NULL, NULL);
 
     Py_RETURN_NONE;
 
@@ -331,7 +336,7 @@ PyTypeObject *get_python_study_project_type(void)
         {
             "discover", py_study_project_discover_binary_content,
             METH_VARARGS,
-            "discover($self, content, /)\n--\n\nExplore a new binary content for the project."
+            "discover($self, content, cache, filter/)\n--\n\nExplore a new binary content for the project."
         },
         {
             "attach", py_study_project_attach_content,
diff --git a/src/analysis/binary.c b/src/analysis/binary.c
index 0da3abf..2bcc88d 100644
--- a/src/analysis/binary.c
+++ b/src/analysis/binary.c
@@ -169,7 +169,7 @@ static GBinContent *g_loaded_binary_get_content(const GLoadedBinary *);
 static const char *g_loaded_binary_get_format_name(const GLoadedBinary *);
 
 /* Assure le désassemblage en différé. */
-static bool g_loaded_binary_analyze(GLoadedBinary *, wgroup_id_t, GtkStatusStack *);
+static bool g_loaded_binary_analyze(GLoadedBinary *, bool, wgroup_id_t, GtkStatusStack *);
 
 /* Prend note d'une variation des instructions désassemblées. */
 static void on_binary_processor_changed(GArchProcessor *, GArchInstruction *, gboolean, GLoadedBinary *);
@@ -1685,6 +1685,7 @@ static const char *g_loaded_binary_get_format_name(const GLoadedBinary *binary)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : binary = élément chargé dont l'analyse est lancée.           *
+*                cache  = précise si la préparation d'un rendu est demandée.  *
 *                gid    = groupe de travail dédié.                            *
 *                status = barre de statut à tenir informée.                   *
 *                                                                             *
@@ -1696,7 +1697,7 @@ static const char *g_loaded_binary_get_format_name(const GLoadedBinary *binary)
 *                                                                             *
 ******************************************************************************/
 
-static bool g_loaded_binary_analyze(GLoadedBinary *binary, wgroup_id_t gid, GtkStatusStack *status)
+static bool g_loaded_binary_analyze(GLoadedBinary *binary, bool cache, wgroup_id_t gid, GtkStatusStack *status)
 {
     bool result;                            /* Bilan à retourner           */
     GBinFormat *format;                     /* Format lié au binaire       */
@@ -1759,7 +1760,7 @@ static bool g_loaded_binary_analyze(GLoadedBinary *binary, wgroup_id_t gid, GtkS
 
     g_binary_format_complete_analysis(format, gid, status);
 
-    if (!is_batch_mode())
+    if (cache)
     {
         output_disassembly(binary, context, status, &binary->disass_cache);
 
diff --git a/src/analysis/loaded-int.h b/src/analysis/loaded-int.h
index face2bb..c1cba2a 100644
--- a/src/analysis/loaded-int.h
+++ b/src/analysis/loaded-int.h
@@ -43,7 +43,7 @@ typedef GBinContent * (* get_content_fc) (const GLoadedContent *);
 typedef const char * (* get_format_name_fc) (const GLoadedContent *);
 
 /* Assure l'analyse d'un contenu chargé en différé. */
-typedef bool (* analyze_loaded_fc) (GLoadedContent *, wgroup_id_t, GtkStatusStack *);
+typedef bool (* analyze_loaded_fc) (GLoadedContent *, bool, wgroup_id_t, GtkStatusStack *);
 
 /* Fournit le désignation associée à l'élément chargé. */
 typedef const char * (* describe_loaded_fc) (const GLoadedContent *, bool);
diff --git a/src/analysis/loaded.c b/src/analysis/loaded.c
index 2343992..6f79bf8 100644
--- a/src/analysis/loaded.c
+++ b/src/analysis/loaded.c
@@ -69,6 +69,7 @@ struct _GLoadedAnalysis
     GDelayedWork parent;                    /* A laisser en premier        */
 
     GLoadedContent *content;                /* Cible de l'analyse à mener  */
+    bool cache;                             /* Degré d'opération à mener   */
 
     bool success;                           /* Bilan de l'opération        */
 
@@ -98,7 +99,7 @@ static void g_loaded_analysis_dispose(GLoadedAnalysis *);
 static void g_loaded_analysis_finalize(GLoadedAnalysis *);
 
 /* Crée une tâche d'analyse de contenu différée. */
-static GLoadedAnalysis *g_loaded_analysis_new(GLoadedContent *);
+static GLoadedAnalysis *g_loaded_analysis_new(GLoadedContent *, bool);
 
 /* Assure l'analyse d'un contenu chargé en différé. */
 static void g_loaded_analysis_process(GLoadedAnalysis *, GtkStatusStack *);
@@ -260,6 +261,7 @@ const char *g_loaded_content_get_format_name(const GLoadedContent *content)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : content = élément chargé à manipuler.                        *
+*                cache   = précise si la préparation d'un rendu est demandée. *
 *                                                                             *
 *  Description : Lance l'analyse propre à l'élément chargé.                   *
 *                                                                             *
@@ -269,12 +271,12 @@ const char *g_loaded_content_get_format_name(const GLoadedContent *content)
 *                                                                             *
 ******************************************************************************/
 
-void g_loaded_content_analyze(GLoadedContent *content)
+void g_loaded_content_analyze(GLoadedContent *content, bool cache)
 {
     GLoadedAnalysis *analysis;              /* Analyse à mener             */
     GWorkQueue *queue;                      /* Gestionnaire de différés    */
 
-    analysis = g_loaded_analysis_new(content);
+    analysis = g_loaded_analysis_new(content, cache);
 
     g_signal_connect(analysis, "work-completed",
                      G_CALLBACK(on_loaded_content_analysis_completed), content);
@@ -309,6 +311,7 @@ static void on_loaded_content_analysis_completed(GLoadedAnalysis *analysis, GLoa
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : content = élément chargé à manipuler.                        *
+*                cache   = précise si la préparation d'un rendu est demandée. *
 *                                                                             *
 *  Description : Lance l'analyse de l'élément chargé et attend sa conclusion. *
 *                                                                             *
@@ -318,14 +321,14 @@ static void on_loaded_content_analysis_completed(GLoadedAnalysis *analysis, GLoa
 *                                                                             *
 ******************************************************************************/
 
-bool g_loaded_content_analyze_and_wait(GLoadedContent *content)
+bool g_loaded_content_analyze_and_wait(GLoadedContent *content, bool cache)
 {
     bool result;                            /* Bilan à retourner           */
     GLoadedAnalysis *analysis;              /* Analyse à mener             */
     GWorkQueue *queue;                      /* Gestionnaire de différés    */
     wgroup_id_t gid;                        /* Identifiant pour les tâches */
 
-    analysis = g_loaded_analysis_new(content);
+    analysis = g_loaded_analysis_new(content, cache);
     g_object_ref(G_OBJECT(analysis));
 
     queue = get_work_queue();
@@ -644,6 +647,7 @@ static void g_loaded_analysis_finalize(GLoadedAnalysis *analysis)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : content = contenu chargé à traiter.                          *
+*                cache   = précise si la préparation d'un rendu est demandée. *
 *                                                                             *
 *  Description : Crée une tâche d'analyse de contenu différée.                *
 *                                                                             *
@@ -653,7 +657,7 @@ static void g_loaded_analysis_finalize(GLoadedAnalysis *analysis)
 *                                                                             *
 ******************************************************************************/
 
-static GLoadedAnalysis *g_loaded_analysis_new(GLoadedContent *content)
+static GLoadedAnalysis *g_loaded_analysis_new(GLoadedContent *content, bool cache)
 {
     GLoadedAnalysis *result;            /* Tâche à retourner           */
 
@@ -662,6 +666,8 @@ static GLoadedAnalysis *g_loaded_analysis_new(GLoadedContent *content)
     result->content = content;
     g_object_ref(G_OBJECT(content));
 
+    result->cache = cache;
+
     return result;
 
 }
@@ -692,7 +698,7 @@ static void g_loaded_analysis_process(GLoadedAnalysis *analysis, GtkStatusStack
 
     gid = g_work_queue_define_work_group(queue);
 
-    analysis->success = iface->analyze(analysis->content, gid, status);
+    analysis->success = iface->analyze(analysis->content, analysis->cache, gid, status);
 
     if (analysis->success)
         handle_loaded_content(PGA_CONTENT_ANALYZED, analysis->content, gid, status);
diff --git a/src/analysis/loaded.h b/src/analysis/loaded.h
index 284efae..1d41cef 100644
--- a/src/analysis/loaded.h
+++ b/src/analysis/loaded.h
@@ -71,10 +71,10 @@ GBinContent *g_loaded_content_get_content(const GLoadedContent *);
 const char *g_loaded_content_get_format_name(const GLoadedContent *);
 
 /* Lance l'analyse propre à l'élément chargé. */
-void g_loaded_content_analyze(GLoadedContent *);
+void g_loaded_content_analyze(GLoadedContent *, bool);
 
 /* Lance l'analyse de l'élément chargé et attend sa conclusion. */
-bool g_loaded_content_analyze_and_wait(GLoadedContent *);
+bool g_loaded_content_analyze_and_wait(GLoadedContent *, bool);
 
 /* Fournit le désignation associée à l'élément chargé. */
 const char *g_loaded_content_describe(const GLoadedContent *, bool);
diff --git a/src/analysis/project.c b/src/analysis/project.c
index 8474610..4574d88 100644
--- a/src/analysis/project.c
+++ b/src/analysis/project.c
@@ -92,7 +92,7 @@ static void g_study_project_finalize(GStudyProject *);
 
 
 /* Assure l'intégration de contenus listés dans du XML. */
-static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *);
+static void g_study_project_recover_binary_contents(GStudyProject *, xmlDoc *, xmlXPathContext *, bool);
 
 
 
@@ -113,6 +113,7 @@ typedef struct _GLoadingHandler
     GDelayedWork parent;                    /* A laisser en premier        */
 
     GStudyProject *project;                 /* Projet à compléter          */
+    bool cache;                             /* Degré d'opération à mener   */
 
     xmlDoc *xdoc;                           /* Structure XML chargée ?     */
     xmlXPathContext *context;               /* Eventuel contexte XML       */
@@ -152,10 +153,10 @@ static void g_loading_handler_dispose(GLoadingHandler *);
 static void g_loading_handler_finalize(GLoadingHandler *);
 
 /* Crée une tâche de chargement de contenu bianire. */
-static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *, GBinContent *, filter_loadable_cb, void *);
+static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *, GBinContent *, bool, filter_loadable_cb, void *);
 
 /* Crée une tâche de chargement de contenu bianire. */
-static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *, xmlDoc *, xmlXPathContext *);
+static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *, xmlDoc *, xmlXPathContext *, bool);
 
 /* Assure le chargement de contenus binaires en différé. */
 static void g_loading_handler_process(GLoadingHandler *, GtkStatusStack *);
@@ -332,6 +333,7 @@ GStudyProject *g_study_project_new(void)
 /******************************************************************************
 *                                                                             *
 *  Paramètres  : filename = chemin d'accès au fichier à charger.              *
+*                cache    = précise si la préparation d'un rendu est demandée.*
 *                                                                             *
 *  Description : Crée un projet à partir du contenu XML d'un fichier.         *
 *                                                                             *
@@ -341,7 +343,7 @@ GStudyProject *g_study_project_new(void)
 *                                                                             *
 ******************************************************************************/
 
-GStudyProject *g_study_project_open(const char *filename)
+GStudyProject *g_study_project_open(const char *filename, bool cache)
 {
     GStudyProject *result;                  /* Adresse à retourner         */
     xmlDoc *xdoc;                           /* Structure XML chargée       */
@@ -353,7 +355,7 @@ GStudyProject *g_study_project_open(const char *filename)
 
     result->filename = strdup(filename);
 
-    g_study_project_recover_binary_contents(result, xdoc, context);
+    g_study_project_recover_binary_contents(result, xdoc, context, cache);
 
     return result;
 
@@ -530,6 +532,7 @@ const char *g_study_project_get_filename(const GStudyProject *project)
 *  Paramètres  : project = projet dont le contenu est à compléter.            *
 *                xdoc    = structure XML en cours d'édition.                  *
 *                context = contexte à utiliser pour les recherches.           *
+*                cache   = précise si la préparation d'un rendu est demandée. *
 *                                                                             *
 *  Description : Assure l'intégration de contenus listés dans du XML.         *
 *                                                                             *
@@ -539,11 +542,11 @@ const char *g_study_project_get_filename(const GStudyProject *project)
 *                                                                             *
 ******************************************************************************/
 
-static void g_study_project_recover_binary_contents(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context)
+static void g_study_project_recover_binary_contents(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context, bool cache)
 {
     GLoadingHandler *handler;               /* Encadrement du chargement   */
 
-    handler = g_loading_handler_new_recovering(project, xdoc, context);
+    handler = g_loading_handler_new_recovering(project, xdoc, context, cache);
 
     if (handler != NULL)
         g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(handler), LOADING_WORK_GROUP);
@@ -555,6 +558,7 @@ static void g_study_project_recover_binary_contents(GStudyProject *project, xmlD
 *                                                                             *
 *  Paramètres  : project = projet dont le contenu est à compléter.            *
 *                content = contenu binaire à mémoriser pour le projet.        *
+*                cache   = précise si la préparation d'un rendu est demandée. *
 *                filter  = procédure de filtrage de contenus chargés.         *
 *                data    = données utiles à la procédure de filtre.           *
 *                                                                             *
@@ -566,11 +570,11 @@ static void g_study_project_recover_binary_contents(GStudyProject *project, xmlD
 *                                                                             *
 ******************************************************************************/
 
-void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content, filter_loadable_cb filter, void *data)
+void g_study_project_discover_binary_content(GStudyProject *project, GBinContent *content, bool cache, filter_loadable_cb filter, void *data)
 {
     GLoadingHandler *handler;               /* Encadrement du chargement   */
 
-    handler = g_loading_handler_new_discovering(project, content, filter, data);
+    handler = g_loading_handler_new_discovering(project, content, cache, filter, data);
 
     g_work_queue_schedule_work(get_work_queue(), G_DELAYED_WORK(handler), LOADING_WORK_GROUP);
 
@@ -920,6 +924,7 @@ static void g_loading_handler_finalize(GLoadingHandler *handler)
 *                                                                             *
 *  Paramètres  : project = projet dont le contenu est à compléter.            *
 *                content = contenu binaire à mémoriser pour le projet.        *
+*                cache   = précise si la préparation d'un rendu est demandée. *
 *                filter  = procédure de filtrage de contenus chargés.         *
 *                data    = données utiles à la procédure de filtre.           *
 *                                                                             *
@@ -931,7 +936,7 @@ static void g_loading_handler_finalize(GLoadingHandler *handler)
 *                                                                             *
 ******************************************************************************/
 
-static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project, GBinContent *content, filter_loadable_cb filter, void *data)
+static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project, GBinContent *content, bool cache, filter_loadable_cb filter, void *data)
 {
     GLoadingHandler *result;                /* Tâche à retourner           */
     GContentExplorer *explorer;             /* Explorateur de contenus     */
@@ -941,6 +946,8 @@ static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project
     result->project = project;
     g_object_ref(G_OBJECT(result->project));
 
+    result->cache = cache;
+
     result->xdoc = NULL;
     result->context = NULL;
 
@@ -972,6 +979,7 @@ static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project
 *  Paramètres  : project = projet dont le contenu est à compléter.            *
 *                xdoc    = structure XML en cours d'édition.                  *
 *                context = contexte à utiliser pour les recherches.           *
+*                cache   = précise si la préparation d'un rendu est demandée. *
 *                                                                             *
 *  Description : Crée une tâche de chargement de contenu bianire.             *
 *                                                                             *
@@ -981,7 +989,7 @@ static GLoadingHandler *g_loading_handler_new_discovering(GStudyProject *project
 *                                                                             *
 ******************************************************************************/
 
-static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context)
+static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *project, xmlDoc *xdoc, xmlXPathContext *context, bool cache)
 {
     GLoadingHandler *result;                /* Tâche à retourner           */
     xmlXPathObjectPtr xobject;              /* Cible d'une recherche       */
@@ -1003,6 +1011,8 @@ static GLoadingHandler *g_loading_handler_new_recovering(GStudyProject *project,
         result->project = project;
         g_object_ref(G_OBJECT(result->project));
 
+        result->cache = cache;
+
         result->xdoc = xdoc;
         result->context = context;
 
@@ -1266,7 +1276,6 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
 
                 if (XPATH_OBJ_NODES_COUNT(xobject) > 0)
                 {
-
                     status = g_loaded_content_restore(available[i], handler->xdoc, handler->context, access);
 
                     if (!status)
@@ -1287,7 +1296,7 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
                         g_signal_connect(available[i], "analyzed",
                                          G_CALLBACK(on_loaded_content_analyzed), handler->project);
 
-                        g_loaded_content_analyze(available[i]);
+                        g_loaded_content_analyze(available[i], handler->cache);
 
                     }
 
@@ -1329,7 +1338,7 @@ static void on_new_content_resolved(GContentResolver *resolver, wgroup_id_t wid,
                         g_signal_connect(available[i], "analyzed",
                                          G_CALLBACK(on_loaded_content_analyzed), handler->project);
 
-                        g_loaded_content_analyze(available[i]);
+                        g_loaded_content_analyze(available[i], handler->cache);
 
                     }
 
diff --git a/src/analysis/project.h b/src/analysis/project.h
index 9b42a47..7ec6239 100644
--- a/src/analysis/project.h
+++ b/src/analysis/project.h
@@ -61,7 +61,7 @@ GType g_study_project_get_type(void);
 GStudyProject *g_study_project_new(void);
 
 /* Crée un projet à partir du contenu XML d'un fichier. */
-GStudyProject *g_study_project_open(const char *);
+GStudyProject *g_study_project_open(const char *, bool);
 
 /* Procède à l'enregistrement d'un projet donné. */
 bool g_study_project_save(GStudyProject *, const char *);
@@ -78,7 +78,7 @@ const char *g_study_project_get_filename(const GStudyProject *);
 typedef bool (* filter_loadable_cb) (GLoadedContent *, void *);
 
 /* Assure l'intégration de contenus binaires dans un projet. */
-void g_study_project_discover_binary_content(GStudyProject *, GBinContent *, filter_loadable_cb, void *);
+void g_study_project_discover_binary_content(GStudyProject *, GBinContent *, bool, filter_loadable_cb, void *);
 
 /* Réceptionne la recette d'une analyse de contenu. */
 void on_loaded_content_analyzed(GLoadedContent *, gboolean, GStudyProject *);
diff --git a/src/gui/editor.c b/src/gui/editor.c
index b52ec9d..205c78f 100644
--- a/src/gui/editor.c
+++ b/src/gui/editor.c
@@ -965,7 +965,7 @@ static void on_editor_contents_available(GStudyProject *project, GLoadedContent
     {
         g_signal_connect(contents[i], "analyzed", G_CALLBACK(on_loaded_content_analyzed), project);
 
-        g_loaded_content_analyze(contents[i]);
+        g_loaded_content_analyze(contents[i], true);
 
         g_object_unref(G_OBJECT(contents[i]));
 
diff --git a/src/gui/menus/file.c b/src/gui/menus/file.c
index d9232db..469aa41 100644
--- a/src/gui/menus/file.c
+++ b/src/gui/menus/file.c
@@ -186,7 +186,7 @@ static void mcb_file_open_project(GtkMenuItem *menuitem, gpointer unused)
     {
         filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
 
-        project = g_study_project_open(filename);
+        project = g_study_project_open(filename, true);
 
         if (project != NULL)
         {
diff --git a/src/gui/menus/project.c b/src/gui/menus/project.c
index 80eff6f..459d963 100644
--- a/src/gui/menus/project.c
+++ b/src/gui/menus/project.c
@@ -205,7 +205,7 @@ static void mcb_project_add_binary_file(GtkMenuItem *menuitem, GMenuBar *bar)
 
         if (content != NULL)
         {
-            g_study_project_discover_binary_content(project, content, NULL, NULL);
+            g_study_project_discover_binary_content(project, content, true, NULL, NULL);
             g_object_unref(G_OBJECT(content));
         }
 
diff --git a/src/gui/panels/welcome.c b/src/gui/panels/welcome.c
index 30652d8..8b74f78 100644
--- a/src/gui/panels/welcome.c
+++ b/src/gui/panels/welcome.c
@@ -602,7 +602,7 @@ static void on_row_activated_for_projects(GtkTreeView *treeview, GtkTreePath *pa
 
         if (valid)
         {
-            project = g_study_project_open(filename);
+            project = g_study_project_open(filename, true);
 
             if (project != NULL)
             {
diff --git a/src/main.c b/src/main.c
index 92df3fa..34aea01 100644
--- a/src/main.c
+++ b/src/main.c
@@ -345,7 +345,7 @@ int main(int argc, char **argv)
 
             if (ret == 0)
             {
-                project = g_study_project_open(prj_filename);
+                project = g_study_project_open(prj_filename, !batch_mode);
                 if (project == NULL) goto bad_project;
             }
 
@@ -440,7 +440,7 @@ static gboolean load_last_project(GGenConfig *cfg)
         filename = NULL;
 
     if (filename == NULL) project = g_study_project_new();
-    else project = g_study_project_open(filename);
+    else project = g_study_project_open(filename, !is_batch_mode());
 
     set_current_project(project);
 
@@ -479,7 +479,7 @@ static int open_binaries(char **files, int count)
 
         if (content != NULL)
         {
-            g_study_project_discover_binary_content(project, content, NULL, NULL);
+            g_study_project_discover_binary_content(project, content, !is_batch_mode(), NULL, NULL);
             g_object_unref(G_OBJECT(content));
         }
 
diff --git a/tests/analysis/Makefile b/tests/analysis/Makefile
new file mode 100644
index 0000000..d15b2c4
--- /dev/null
+++ b/tests/analysis/Makefile
@@ -0,0 +1,10 @@
+
+EXECUTABLES=hm
+
+all: $(EXECUTABLES)
+
+hm: hm.c
+	$(ARM_CROSS)gcc $< -o $@
+
+clean:
+	rm -f $(EXECUTABLES)
diff --git a/tests/analysis/hm.c b/tests/analysis/hm.c
new file mode 100644
index 0000000..9d49352
--- /dev/null
+++ b/tests/analysis/hm.c
@@ -0,0 +1,20 @@
+
+#include <stdio.h>
+#include <string.h>
+
+int main(int argc, char **argv)
+{
+    int a;
+    char cmd[128];
+
+    memcpy(&a, (int []) { 4 }, sizeof(int));
+
+    sprintf(cmd, "cat /proc/%d/maps", getpid());
+
+    system(cmd);
+
+    printf("Hello %d\n", a);
+
+    return 0;
+
+}
diff --git a/tests/analysis/project.py b/tests/analysis/project.py
new file mode 100644
index 0000000..c38463e
--- /dev/null
+++ b/tests/analysis/project.py
@@ -0,0 +1,81 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+
+# S'assure du bon fonctionnement des blocs basiques
+
+
+from chrysacase import ChrysalideTestCase
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.analysis import StudyProject
+from pychrysalide.core import wait_for_all_global_works
+import os
+import sys
+
+
+class TestProjectFeatures(ChrysalideTestCase):
+    """TestCase for projects."""
+
+    @classmethod
+    def setUpClass(cls):
+
+        super(TestProjectFeatures, cls).setUpClass()
+
+        cls.log('Compile binary "hm" if needed...')
+
+        fullname = sys.modules[cls.__module__].__file__
+        dirpath = os.path.dirname(fullname)
+
+        os.system('make -C %s hm > /dev/null 2>&1' % dirpath)
+
+
+    @classmethod
+    def tearDownClass(cls):
+
+        super(TestProjectFeatures, cls).tearDownClass()
+
+        cls.log('Delete built binaries...')
+
+        fullname = sys.modules[cls.__module__].__file__
+        dirpath = os.path.dirname(fullname)
+
+        os.system('make -C %s clean > /dev/null 2>&1' % dirpath)
+
+
+    def testDisassemblyCache(self):
+        """Check disassembly cache availability for loaded binaries."""
+
+        fullname = sys.modules[self.__class__.__module__].__file__
+        filename = os.path.basename(fullname)
+
+        baselen = len(fullname) - len(filename)
+
+        cnt = FileContent(fullname[:baselen] + 'hm')
+        self.assertIsNotNone(cnt)
+
+        prj = StudyProject()
+        prj.discover(cnt, True)
+
+        wait_for_all_global_works()
+
+        self.assertTrue(len(prj.contents) == 1)
+
+        binary = prj.contents[0]
+
+        self.assertIsNotNone(binary)
+        self.assertIsNotNone(binary.disassembled_cache)
+
+        cnt = FileContent(fullname[:baselen] + 'hm')
+        self.assertIsNotNone(cnt)
+
+        prj = StudyProject()
+        prj.discover(cnt)
+
+        wait_for_all_global_works()
+
+        self.assertTrue(len(prj.contents) == 1)
+
+        binary = prj.contents[0]
+
+        self.assertIsNotNone(binary)
+        self.assertIsNone(binary.disassembled_cache)
-- 
cgit v0.11.2-87-g4458