/* OpenIDA - Outil d'analyse de fichiers binaires
 * line_comment.c - représentation des lignes commentaires entières
 *
 * Copyright (C) 2008 Cyrille Bagard
 *
 *  This file is part of OpenIDA.
 *
 *  OpenIDA 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.
 *
 *  OpenIDA 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 Foobar.  If not, see .
 */
#include "line_comment.h"
#include 
#include 
#include "line-int.h"
/* Ligne de représentation de commentaires entière (instance) */
struct _GCommentLine
{
    GRenderingLine parent;                  /* Instance parente            */
    char *comment;                          /* Texte à afficher            */
    const GRenderingOptions *options;       /* Options de représentation   */
};
/* Ligne de représentation de commentaires entière (classe) */
struct _GCommentLineClass
{
    GRenderingLineClass parent;             /* Classe parente              */
};
/* Initialise la classe des lignes de commentaires entière. */
static void g_comment_line_class_init(GCommentLineClass *);
/* Initialise la classe des lignes de commentaires entière. */
static void g_comment_line_init(GCommentLine *);
/* Met à jour la ligne de représentation de commentaires. */
void g_comment_line_refresh_markup(GCommentLine *, MainRendering);
/* Indique le type définit par la GLib pour la ligne. */
G_DEFINE_TYPE(GCommentLine, g_comment_line, G_TYPE_RENDERING_LINE);
/******************************************************************************
*                                                                             *
*  Paramètres  : klass = classe à initialiser.                                *
*                                                                             *
*  Description : Initialise la classe des lignes de commentaires entière.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_comment_line_class_init(GCommentLineClass *klass)
{
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line = instance à initialiser.                               *
*                                                                             *
*  Description : Initialise la classe des lignes de commentaires entière.     *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
static void g_comment_line_init(GCommentLine *line)
{
    GRenderingLine *parent;                 /* Instance parente            */
    parent = G_RENDERING_LINE(line);
    parent->type = RLT_PROTOTYPE/* TODO */;
    parent->refresh_markup = (refresh_markup_fc)g_comment_line_refresh_markup;
}
/******************************************************************************
*                                                                             *
*  Paramètres  : line      = ligne de représentation à actualiser.            *
*                rendering = support effectif final des lignes de code.       *
*                                                                             *
*  Description : Met à jour la ligne de représentation de commentaires.       *
*                                                                             *
*  Retour      : -                                                            *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
void g_comment_line_refresh_markup(GCommentLine *line, MainRendering rendering)
{
    bool show_address;                      /* Affichage de l'adresse ?    */
    bool show_code;                         /* Affichage du code brut ?    */
    size_t len;                             /* Taille du contenu           */
    char *content;                          /* Contenu réellement imprimé  */
    char buffer[CODE_BUFFER_LEN];           /* Zone tampon à utiliser      */
    const off_t *max_bin_len;               /* Taille de ligne max/globale */
    size_t clen;                            /* Taille du commentaire       */
    show_address = g_rendering_options_has_to_show_address(line->options, rendering);
    show_code = g_rendering_options_has_to_show_code(line->options, rendering);
    len = strlen("") + 1;
    content = (char *)calloc(len, sizeof(char));
    strcpy(content, "");
    /* Eventuelle adresse virtuelle */
    if (show_address)
    {
        switch (g_arch_processor_get_memory_size(g_rendering_options_get_processor(line->options)))
        {
            case MDS_8_BITS:
                snprintf(buffer, CODE_BUFFER_LEN,
                         "0x%02llx",
                         G_RENDERING_LINE(line)->offset);
                break;
            case MDS_16_BITS:
                snprintf(buffer, CODE_BUFFER_LEN,
                         "0x%04llx",
                         G_RENDERING_LINE(line)->offset);
                break;
            case MDS_32_BITS:
                snprintf(buffer, CODE_BUFFER_LEN,
                         "0x%08llx",
                         G_RENDERING_LINE(line)->offset);
                break;
            default:
            case MDS_64_BITS:
                snprintf(buffer, CODE_BUFFER_LEN,
                         "0x%16llx",
                         G_RENDERING_LINE(line)->offset);
                break;
        }
        len += strlen(buffer);
        content = (char *)realloc(content, len * sizeof(char));
        strcat(content, buffer);
    }
    /* Eventuel code brut (sauté) */
    if (show_code)
    {
        max_bin_len = &G_RENDERING_LINE(line)->max_bin_len[rendering];
        clen = (show_address ? strlen("\t") : 0);
        clen += *max_bin_len;
        content = (char *)realloc(content, (len + clen) * sizeof(char));
        if (show_address)
        {
            strcat(content, "\t");
            len += strlen("\t");
        }
        memset(&content[len - 1],
               G_RENDERING_LINE(line)->type == RLT_PROTOTYPE ? '-' : ' ', *max_bin_len);
        len += *max_bin_len;
        content[len - 1] = '\0';
    }
    /* Commentaire proprement dit */
    clen = (show_address || show_code ? strlen("\t") : 0);
    clen += strlen("");
    clen += strlen("; ") + strlen(line->comment);
    clen += strlen("");
    content = (char *)realloc(content, (len + clen) * sizeof(char));
    if (show_address || show_code)
    {
        strcat(content, "\t");
        len += strlen("\t");
        clen -= strlen("\t");
    }
    snprintf(&content[len - 1], clen + 1, "; %s", line->comment);
    len += clen;
    /* Finalisation */
    len += strlen("");
    content = (char *)realloc(content, len * sizeof(char));
    strcat(content, "");
    pango_layout_set_markup(G_RENDERING_LINE(line)->layout[rendering], content, len - 1);
    free(content);
}
/******************************************************************************
*                                                                             *
*  Paramètres  : offset  = emplacement physique ou en mémoire.                *
*                comment = texte à afficher au final.                         *
*                options = paramétrage du rendu.                              *
*                                                                             *
*  Description : Crée une ligne de commentaires entière.                      *
*                                                                             *
*  Retour      : Adresse de la structure mise en place.                       *
*                                                                             *
*  Remarques   : -                                                            *
*                                                                             *
******************************************************************************/
GRenderingLine *g_comment_line_new(uint64_t offset, const char *comment, const GRenderingOptions *options)
{
    GCommentLine *result;                   /* Structure à retourner       */
    result = g_object_new(G_TYPE_COMMENT_LINE, NULL);
    G_RENDERING_LINE(result)->offset = offset;
    result->comment = strdup(comment);
    result->options = options;
    return G_RENDERING_LINE(result);
}