summaryrefslogtreecommitdiff
path: root/src/glibext/helpers.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/glibext/helpers.h')
-rw-r--r--src/glibext/helpers.h166
1 files changed, 166 insertions, 0 deletions
diff --git a/src/glibext/helpers.h b/src/glibext/helpers.h
new file mode 100644
index 0000000..752eb07
--- /dev/null
+++ b/src/glibext/helpers.h
@@ -0,0 +1,166 @@
+
+/* Chrysalide - Outil d'analyse de fichiers binaires
+ * helpers.h - prototypes pour la simplification des interactions de base avec GLib
+ *
+ * Copyright (C) 2024 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 Chrysalide. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef _GLIBEXT_HELPERS_H
+#define _GLIBEXT_HELPERS_H
+
+
+#include <assert.h>
+#include <glib-object.h>
+
+
+
+/**
+ * Les définitions issues de <glib-2.80>/gobject/gtype.h fournissent des macros
+ * facilitant la déclaration de types pour entêtes. Cependant :
+ *
+ * - G_DECLARE_FINAL_TYPE impose une structure de classe fixe ;
+ * - G_DECLARE_DERIVABLE_TYPE impose une structure d'objet fixe.
+ *
+ * Ces deux macros ne peuvent donc pas être employées en l'état dans Chrysalide.
+ *
+ * Par ailleurs, la fonctionnalité g_autoptr() n'offre pas une séduction totale :
+ * elle conduit à un code inconsistant, avec parfois des libérations explicites,
+ * parfois des libérations invisible gérées par le compilateur. Cet aspect
+ * fonctionnel offert par les macros GLib est donc inutile pour Chrysalide.
+ *
+ * Une nouvelle macro de déclaration est ainsi constituée ici.
+ *
+ * De fait de l'absence d'argument, l'inclusion de la définition suivante n'est
+ * pas possible :
+ *
+ * MOD##_TYPE_##NAME t_n##_get_type()
+ *
+ * La macro traditionnelle doit ainsi être fournie en parallèle à la déclaration
+ * condensée ici. Elle y est d'ailleurs référencée, forçant une déclaration
+ * préalable de manière globale et cohérente dans l'ensemble du code d'emploi.
+ */
+
+#define DECLARE_GTYPE(TN, t_n, MOD, NAME) \
+ \
+ GType t_n##_get_type(void); \
+ \
+ typedef struct _##TN TN; \
+ typedef struct _##TN##Class TN##Class; \
+ \
+ G_GNUC_UNUSED static inline TN *MOD##_##NAME(gpointer obj) \
+ { \
+ return G_TYPE_CHECK_INSTANCE_CAST(obj, MOD##_TYPE_##NAME, TN); \
+ } \
+ \
+ G_GNUC_UNUSED static inline TN##Class *MOD##_##NAME##_CLASS(gpointer klass) \
+ { \
+ return G_TYPE_CHECK_CLASS_CAST(klass, MOD##_TYPE_##NAME, TN##Class); \
+ } \
+ \
+ G_GNUC_UNUSED static inline gboolean MOD##_IS_##NAME(gpointer obj) \
+ { \
+ return G_TYPE_CHECK_INSTANCE_TYPE(obj, MOD##_TYPE_##NAME); \
+ } \
+ \
+ G_GNUC_UNUSED static inline gboolean MOD##_IS_##NAME##_CLASS(gpointer klass) \
+ { \
+ return G_TYPE_CHECK_CLASS_TYPE(klass, MOD##_TYPE_##NAME); \
+ } \
+ \
+ G_GNUC_UNUSED static inline TN##Class *MOD##_##NAME##_GET_CLASS(gpointer obj) \
+ { \
+ return G_TYPE_INSTANCE_GET_CLASS(obj, MOD##_TYPE_##NAME, TN##Class); \
+ }
+
+
+/**
+ * Les principales fonctions incrémentant ou réduisant le nombre de références
+ * attachées à un objet acceptent de simples pointeurs génériques (cf. définitions
+ * du fichier <glib-2.80>/gobject/gobject.h :
+ *
+ * [...]
+ * void g_object_notify_by_pspec (GObject *object,
+ * GParamSpec *pspec);
+ * void g_object_thaw_notify (GObject *object);
+ * gboolean g_object_is_floating (gpointer object);
+ * gpointer g_object_ref_sink (gpointer object);
+ * gpointer g_object_take_ref (gpointer object);
+ * gpointer g_object_ref (gpointer object);
+ * void g_object_unref (gpointer object);
+ * void g_object_weak_ref (GObject *object,
+ * GWeakNotify notify,
+ * gpointer data);
+ * [...]
+ *
+ * La fonction g_object_unref() débute bien par exemple par une validation
+ * de l'instance, avec un appel à : g_return_if_fail (G_IS_OBJECT (object)).
+ *
+ * Cependant, cette vérification est désactivée en cas de compilation de GLib
+ * avec G_DISABLE_CHECKS.
+ *
+ * Une conversion vers un type donné (par exemple avec G_OBJECT()) est par
+ * ailleurs dépendante d'autres paramètres de compilation, comme le révèle
+ * le fichier <glib-2.80>/gobject/gtype.h :
+ *
+ * #if defined(G_DISABLE_CAST_CHECKS) || defined(__OPTIMIZE__)
+ * # define _G_TYPE_CIC(ip, gt, ct) ((ct*) (void *) ip)
+ * # define _G_TYPE_CCC(cp, gt, ct) ((ct*) (void *) cp)
+ * #else
+ * # define _G_TYPE_CIC(ip, gt, ct) \
+ * ((ct*) (void *) g_type_check_instance_cast ((GTypeInstance*) ip, gt))
+ * # define _G_TYPE_CCC(cp, gt, ct) \
+ * ((ct*) (void *) g_type_check_class_cast ((GTypeClass*) cp, gt))
+ * #endif
+ *
+ * Afin d'assurer des conditions de débogage/fuzzing optimales dans tous les
+ * cas de figure, les fonctions de manipulation des références font l'objet
+ * ici d'une couche intermédiaire pour les appels.
+ */
+
+#ifndef NDEBUG
+
+# define ref_object(ip) \
+ do \
+ { \
+ GTypeInstance *__inst; \
+ __inst = g_type_check_instance_cast((GTypeInstance *)ip, G_TYPE_OBJECT); \
+ assert(__inst != NULL); \
+ g_object_ref(ip); \
+ } \
+ while (0);
+
+# define unref_object(ip) \
+ do \
+ { \
+ GTypeInstance *__inst; \
+ __inst = g_type_check_instance_cast((GTypeInstance *)ip, G_TYPE_OBJECT); \
+ assert(__inst != NULL); \
+ g_object_unref(ip); \
+ } \
+ while (0);
+
+#else
+
+# define ref_object(p) g_object_ref(p)
+# define unref_object(p) g_object_unref(p)
+
+#endif
+
+
+#endif /* _GLIBEXT_HELPERS_H */