/* Chrysalide - Outil d'analyse de fichiers binaires
 * native.c - interactions avec un greffon natif donné
 *
 * Copyright (C) 2025 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */


#include "native.h"


#include "native-int.h"
#include "../common/cpp.h"



/* ------------------------- COMPOSITION DE NOUVEAU GREFFON ------------------------- */


/* Initialise la classe des greffons natifs. */
static void g_native_plugin_class_init(GNativePluginClass *);

/* Initialise une instance de greffon natif. */
static void g_native_plugin_init(GNativePlugin *);

/* Supprime toutes les références externes. */
static void g_native_plugin_dispose(GNativePlugin *);

/* Procède à la libération totale de la mémoire. */
static void g_native_plugin_finalize(GNativePlugin *);



/* --------------------- IMPLEMENTATION DES FONCTIONS DE CLASSE --------------------- */


/* Pointe le fichier contenant le greffon manipulé. */
static char *g_native_plugin_get_filename(const GNativePlugin *);

/* Fournit le nom brut associé au greffon. */
static char *g_native_plugin_get_modname(const GNativePlugin *);



/* ---------------------------------------------------------------------------------- */
/*                           COMPOSITION DE NOUVEAU GREFFON                           */
/* ---------------------------------------------------------------------------------- */


/* Indique le type défini pour un greffon Python. */
G_DEFINE_TYPE(GNativePlugin, g_native_plugin, G_TYPE_PLUGIN_MODULE);



/******************************************************************************
*                                                                             *
*  Paramètres  : class = classe à initialiser.                                *
*                                                                             *
*  Description : Initialise la classe des greffons natifs.                    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_native_plugin_class_init(GNativePluginClass *class)
{
    GObjectClass *object;                   /* Autre version de la classe  */
    GPluginModuleClass *plugin;             /* Version parente de la classe*/

    object = G_OBJECT_CLASS(class);

    object->dispose = (GObjectFinalizeFunc/* ! */)g_native_plugin_dispose;
    object->finalize = (GObjectFinalizeFunc)g_native_plugin_finalize;

    plugin = G_PLUGIN_MODULE_CLASS(class);

    plugin->get_filename = (get_plugin_filename_fc)g_native_plugin_get_filename;
    plugin->get_modname = (get_plugin_modname_fc)g_native_plugin_get_modname;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : plugin = instance à initialiser.                             *
*                                                                             *
*  Description : Initialise une instance de greffon natif.                    *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_native_plugin_init(GNativePlugin *plugin)
{
    plugin->module = NULL;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
*                                                                             *
*  Description : Supprime toutes les références externes.                     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_native_plugin_dispose(GNativePlugin *plugin)
{
    G_OBJECT_CLASS(g_native_plugin_parent_class)->dispose(G_OBJECT(plugin));

}


/******************************************************************************
*                                                                             *
*  Paramètres  : plugin = instance d'objet GLib à traiter.                    *
*                                                                             *
*  Description : Procède à la libération totale de la mémoire.                *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static void g_native_plugin_finalize(GNativePlugin *plugin)
{
    G_OBJECT_CLASS(g_native_plugin_parent_class)->finalize(G_OBJECT(plugin));

}


/******************************************************************************
*                                                                             *
*  Paramètres  : plugin   = instance à initialiser pleinement.                *
*                name     = nom du greffon pour référence, principalement.    *
*                desc     = présentation éventuelle à destination humaine.    *
*                version  = indication de version éventuelle.                 *
*                url      = référence vers une ressource en ligne.            *
*                required = liste de dépendances éventuelles ou NULL.         *
*                count    = taille de cette liste.                            *
*                module   = extension vue du système.                         *
*                                                                             *
*  Description : Met en place un greffon natif.                               *
*                                                                             *
*  Retour      : Bilan de l'opération.                                        *
*                                                                             *
*  Remarques   : Le transfert de propriétée du module est total.              *
*                                                                             *
******************************************************************************/

bool g_native_plugin_create(GNativePlugin *plugin, const char *name, const char *desc, const char *version, const char *url, const char * const *required, size_t count, GModule *module)
{
    bool result;                            /* Bilan à retourner           */

    result = g_plugin_module_create(G_PLUGIN_MODULE(plugin), name, desc, version, url, required, count);

    if (result)
        plugin->module = module;

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : plugin = greffon à consulter.                                *
*                                                                             *
*  Description : Renvoie la structure opaque associée au module en mémoire.   *
*                                                                             *
*  Retour      : Structure de chargement côté GLib.                           *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

GModule *g_native_plugin_get_module(const GNativePlugin *plugin)
{
    GModule *result;                        /* Accès au module à renvoyer  */

    result = plugin->module;

    return result;

}



/* ---------------------------------------------------------------------------------- */
/*                       IMPLEMENTATION DES FONCTIONS DE CLASSE                       */
/* ---------------------------------------------------------------------------------- */


/******************************************************************************
*                                                                             *
*  Paramètres  : plugin = greffon à consulter.                                *
*                                                                             *
*  Description : Pointe le fichier contenant le greffon manipulé.             *
*                                                                             *
*  Retour      : Chemin d'accès au greffon.                                   *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static char *g_native_plugin_get_filename(const GNativePlugin *plugin)
{
    char *result;                           /* Chemin d'accès à renvoyer   */

    result = strdup(g_module_name(plugin->module));

    return result;

}


/******************************************************************************
*                                                                             *
*  Paramètres  : plugin = greffon à valider.                                  *
*                                                                             *
*  Description : Fournit le nom brut associé au greffon.                      *
*                                                                             *
*  Retour      : Désignation brute du greffon.                                *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/

static char *g_native_plugin_get_modname(const GNativePlugin *plugin)
{
    char *result;                           /* Désignation brute à renvoyer*/
    char *path;                             /* Chemin à traiter            */
    char *filename;                         /* Nom de bibliothèque partagée*/
    size_t length;                          /* Taille du nom               */
    int ret;                                /* Bilan d'une comparaison     */

    path = g_native_plugin_get_filename(plugin);

    filename = basename(path);

    if (strncmp(filename, "lib", 3) == 0)
        filename += 3;

    length = strlen(filename);

#ifdef _WIN32
#   define SHARED_SUFFIX ".dll"
#else
#   define SHARED_SUFFIX ".so"
#endif

    if (length >= STATIC_STR_SIZE(SHARED_SUFFIX))
    {
        ret = strncmp(&filename[length - STATIC_STR_SIZE(SHARED_SUFFIX)],
                      SHARED_SUFFIX,
                      STATIC_STR_SIZE(SHARED_SUFFIX));

        if (ret == 0)
            filename[length - STATIC_STR_SIZE(SHARED_SUFFIX)] = '\0';

    }

    result = strdup(filename);

    free(path);

    return result;

}