/* Chrysalide - Outil d'analyse de fichiers binaires
* type.h - prototypes pour la manipulation des types en tout genre
*
* Copyright (C) 2010-2018 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 .
*/
#include "type.h"
#include
#include
#include "type-int.h"
#include "storage/serialize.h"
#include "../common/extstr.h"
/* Initialise la classe des types quelconques. */
static void g_data_type_class_init(GDataTypeClass *);
/* Initialise l'instance d'un type quelconque. */
static void g_data_type_init(GDataType *);
/* Procède à l'initialisation de l'interface de sérialisation. */
static void g_serializable_object_interface_init(GSerializableObjectIface *);
/* Supprime toutes les références externes. */
static void g_data_type_dispose(GDataType *);
/* Procède à la libération totale de la mémoire. */
static void g_data_type_finalize(GDataType *);
/* Charge un objet depuis une mémoire tampon. */
static bool _g_data_type_load(GDataType *, GObjectStorage *, packed_buffer *);
/* Charge un objet depuis une mémoire tampon. */
static bool g_data_type_load(GDataType *, GObjectStorage *, packed_buffer *);
/* Sauvegarde un objet dans une mémoire tampon. */
static bool _g_data_type_store(const GDataType *, GObjectStorage *, packed_buffer *);
/* Sauvegarde un objet dans une mémoire tampon. */
static bool g_data_type_store(const GDataType *, GObjectStorage *, packed_buffer *);
/* Indique le type défini pour un type quelconque. */
G_DEFINE_TYPE_WITH_CODE(GDataType, g_data_type, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE(G_TYPE_SERIALIZABLE_OBJECT, g_serializable_object_interface_init));
/******************************************************************************
* *
* Paramètres : klass = classe à initialiser. *
* *
* Description : Initialise la classe des types quelconques. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_data_type_class_init(GDataTypeClass *klass)
{
GObjectClass *object; /* Autre version de la classe */
object = G_OBJECT_CLASS(klass);
object->dispose = (GObjectFinalizeFunc/* ! */)g_data_type_dispose;
object->finalize = (GObjectFinalizeFunc)g_data_type_finalize;
klass->load = (type_load_fc)_g_data_type_load;
klass->store = (type_store_fc)_g_data_type_store;
}
/******************************************************************************
* *
* Paramètres : type = instance à initialiser. *
* *
* Description : Initialise l'instance d'un type quelconque. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_data_type_init(GDataType *type)
{
g_data_type_set_qualifiers(type, TQF_NONE);
type->namespace = NULL;
type->ns_sep = NULL;
}
/******************************************************************************
* *
* Paramètres : iface = interface GLib à initialiser. *
* *
* Description : Procède à l'initialisation de l'interface de sérialisation. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_serializable_object_interface_init(GSerializableObjectIface *iface)
{
iface->load = (load_serializable_object_cb)g_data_type_load;
iface->store = (store_serializable_object_cb)g_data_type_store;
}
/******************************************************************************
* *
* Paramètres : type = instance d'objet GLib à traiter. *
* *
* Description : Supprime toutes les références externes. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_data_type_dispose(GDataType *type)
{
g_clear_object(&type->namespace);
G_OBJECT_CLASS(g_data_type_parent_class)->dispose(G_OBJECT(type));
}
/******************************************************************************
* *
* Paramètres : type = instance d'objet GLib à traiter. *
* *
* Description : Procède à la libération totale de la mémoire. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
static void g_data_type_finalize(GDataType *type)
{
if (type->ns_sep != NULL)
free(type->ns_sep);
G_OBJECT_CLASS(g_data_type_parent_class)->finalize(G_OBJECT(type));
}
/******************************************************************************
* *
* Paramètres : type = type de données à constuire. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à remplir. *
* *
* Description : Charge un objet depuis une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool _g_data_type_load(GDataType *type, GObjectStorage *storage, packed_buffer *pbuf)
{
bool result; /* Bilan à retourner */
uint8_t has_ns; /* Association d'un espace ? */
uleb128_t value; /* Valeur ULEB128 à charger */
result = unpack_uleb128(&value, pbuf);
if (!result) goto exit;
g_data_type_set_qualifiers(type, value);
result = extract_packed_buffer(pbuf, &has_ns, sizeof(uint8_t), false);
if (!result) goto exit;
if (has_ns == 0x01)
{
result = g_data_type_load(type->namespace, storage, pbuf);
if (!result) goto exit;
result = unpack_uleb128(&value, pbuf);
if (!result) goto exit;
type->ns_sep = calloc(value, sizeof(char));
result = extract_packed_buffer(pbuf, type->ns_sep, value, false);
}
exit:
return result;
}
/******************************************************************************
* *
* Paramètres : type = type de données à constuire. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à remplir. *
* *
* Description : Charge un objet depuis une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_data_type_load(GDataType *type, GObjectStorage *storage, packed_buffer *pbuf)
{
bool result; /* Bilan à retourner */
GDataTypeClass *class; /* Classe du type */
class = G_DATA_TYPE_GET_CLASS(type);
result = class->load(type, storage, pbuf);
return result;
}
/******************************************************************************
* *
* Paramètres : type = type de données à consulter. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à remplir. *
* *
* Description : Sauvegarde un objet dans une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool _g_data_type_store(const GDataType *type, GObjectStorage *storage, packed_buffer *pbuf)
{
bool result; /* Bilan à retourner */
uint8_t has_ns; /* Association d'un espace ? */
size_t ns_sep_len; /* Taille du séparateur */
result = pack_uleb128((uleb128_t []){ g_data_type_get_qualifiers(type) }, pbuf);
if (!result) goto exit;
has_ns = (type->namespace != NULL ? 0x01 : 0x00);
result = extend_packed_buffer(pbuf, &has_ns, sizeof(uint8_t), false);
if (!result) goto exit;
if (type->namespace != NULL)
{
result = g_data_type_store(type->namespace, storage, pbuf);
if (!result) goto exit;
ns_sep_len = strlen(type->ns_sep);
result = pack_uleb128((uleb128_t []){ ns_sep_len }, pbuf);
if (!result) goto exit;
result = extend_packed_buffer(pbuf, type->ns_sep, ns_sep_len, false);
}
exit:
return result;
}
/******************************************************************************
* *
* Paramètres : type = type de données à consulter. *
* storage = conservateur de données à manipuler ou NULL. *
* pbuf = zone tampon à remplir. *
* *
* Description : Sauvegarde un objet dans une mémoire tampon. *
* *
* Retour : Bilan de l'opération. *
* *
* Remarques : - *
* *
******************************************************************************/
static bool g_data_type_store(const GDataType *type, GObjectStorage *storage, packed_buffer *pbuf)
{
bool result; /* Bilan à retourner */
GDataTypeClass *class; /* Classe du type */
class = G_DATA_TYPE_GET_CLASS(type);
result = class->store(type, storage, pbuf);
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à consulter. *
* *
* Description : Calcule une empreinte pour un type de données. *
* *
* Retour : Valeur arbitraire sur 32 bits, idéalement unique par type. *
* *
* Remarques : - *
* *
******************************************************************************/
guint g_data_type_hash(const GDataType *type)
{
guint result; /* Empreinte à renvoyer */
GDataTypeClass *class; /* Classe du type */
class = G_DATA_TYPE_GET_CLASS(type);
result = class->hash(type);
result ^= g_int_hash((gint []){ g_data_type_get_qualifiers(type) });
if (type->namespace != NULL)
result ^= g_data_type_hash(type->namespace);
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à dupliquer. *
* *
* Description : Crée un copie d'un type existant. *
* *
* Retour : Nouvelle instance de type identique à celle fournie. *
* *
* Remarques : - *
* *
******************************************************************************/
GDataType *g_data_type_dup(const GDataType *type)
{
GDataType *result; /* Copie à retourner */
GDataTypeClass *class; /* Classe du type */
GDataType *ns; /* Eventuel espace de noms */
char *ns_sep; /* Séparation des espaces */
class = G_DATA_TYPE_GET_CLASS(type);
result = class->dup(type);
if (type->namespace != NULL)
{
ns = g_data_type_dup(type->namespace);
ns_sep = type->ns_sep != NULL ? strdup(type->ns_sep) : NULL;
g_data_type_set_namespace(result, ns, ns_sep);
}
result->qualifiers = type->qualifiers;
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à convertir. *
* include = doit-on inclure les espaces de noms ? *
* *
* Description : Décrit le type fourni sous forme de caractères. *
* *
* Retour : Chaîne à libérer de la mémoire après usage. *
* *
* Remarques : - *
* *
******************************************************************************/
char *g_data_type_to_string(const GDataType *type, bool include)
{
char *result; /* Chaîne à retourner */
GDataTypeClass *class; /* Classe du type */
char *namespace; /* Groupe d'appartenance */
class = G_DATA_TYPE_GET_CLASS(type);
result = class->to_string(type, include);
if (result == NULL)
result = strdup("");
if (include && type->namespace != NULL && g_data_type_handle_namespaces(type))
{
namespace = g_data_type_to_string(type->namespace, true);
result = strprep(result, type->ns_sep);
result = strprep(result, namespace);
free(namespace);
}
if (type->qualifiers & TQF_RESTRICT)
result = strprep(result, "restrict ");
if (type->qualifiers & TQF_VOLATILE)
result = strprep(result, "volatile ");
if (type->qualifiers & TQF_CONST)
result = strprep(result, "const ");
return result;
}
/******************************************************************************
* *
* Paramètres : type = instance à mettre à jour. *
* qualifiers = nouveaux qualificatifs pour la variable. *
* *
* Description : Définit l'ensemble des qualificatifs d'une instance de type. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_data_type_set_qualifiers(GDataType *type, TypeQualifier qualifiers)
{
type->qualifiers = qualifiers;
}
/******************************************************************************
* *
* Paramètres : type = instance à mettre à jour. *
* qualifier = nouveau qualificatif pour la variable. *
* *
* Description : Ajoute un qualificatif à une instance de type. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_data_type_add_qualifier(GDataType *type, TypeQualifier qualifier)
{
type->qualifiers |= qualifier;
}
/******************************************************************************
* *
* Paramètres : type = instance à consulter. *
* *
* Description : Fournit les qualificatifs associés à une instance de type. *
* *
* Retour : Qualificatifs éventuels. *
* *
* Remarques : - *
* *
******************************************************************************/
TypeQualifier g_data_type_get_qualifiers(const GDataType *type)
{
TypeQualifier result; /* Qualificatifs à renvoyer */
result = type->qualifiers;
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à mettre à jour. *
* namespace = instance d'appartenance. *
* sep = séparateur à utiliser entre les éléments. *
* *
* Description : Définit le groupe d'appartenance d'un type donné. *
* *
* Retour : - *
* *
* Remarques : - *
* *
******************************************************************************/
void g_data_type_set_namespace(GDataType *type, GDataType *namespace, char *sep)
{
if (type->namespace != NULL)
g_object_unref(G_OBJECT(type->namespace));
if (type->ns_sep != NULL)
free(type->ns_sep);
type->namespace = namespace;
type->ns_sep = sep;
}
/******************************************************************************
* *
* Paramètres : type = type à consulter. *
* *
* Description : Fournit le groupe d'appartenance d'un type donné. *
* *
* Retour : Eventuelle instance d'appartenance ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
GDataType *g_data_type_get_namespace(const GDataType *type)
{
GDataType *result; /* Espace à renvoyer */
result = type->namespace;
if (result != NULL)
g_object_ref(G_OBJECT(result));
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à consulter. *
* *
* Description : Fournit la chaîne de séparation entre deux entités. *
* *
* Retour : Eventuelle chaîne de séparation ou NULL. *
* *
* Remarques : - *
* *
******************************************************************************/
const char *g_data_type_get_namespace_separator(const GDataType *type)
{
char *result; /* Séparateur à retourner */
result = type->ns_sep;
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à consulter. *
* *
* Description : Indique si le type assure une gestion des espaces de noms. *
* *
* Retour : Bilan de la consultation. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_data_type_handle_namespaces(const GDataType *type)
{
bool result; /* Bilan à retourner */
GDataTypeClass *class; /* Classe du type */
class = G_DATA_TYPE_GET_CLASS(type);
if (class->handle_ns != NULL)
result = class->handle_ns(type);
else
result = true;
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à consulter. *
* *
* Description : Indique si le type est un pointeur. *
* *
* Retour : Bilan de la consultation. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_data_type_is_pointer(const GDataType *type)
{
bool result; /* Bilan à retourner */
GDataTypeClass *class; /* Classe du type */
class = G_DATA_TYPE_GET_CLASS(type);
if (class->is_pointer != NULL)
result = class->is_pointer(type);
else
result = false;
return result;
}
/******************************************************************************
* *
* Paramètres : type = type à consulter. *
* *
* Description : Indique si le type est une référence. *
* *
* Retour : Bilan de la consultation. *
* *
* Remarques : - *
* *
******************************************************************************/
bool g_data_type_is_reference(const GDataType *type)
{
bool result; /* Bilan à retourner */
GDataTypeClass *class; /* Classe du type */
class = G_DATA_TYPE_GET_CLASS(type);
if (class->is_reference != NULL)
result = class->is_reference(type);
else
result = false;
return result;
}