view tools/data2inc.c @ 2208:90ec1ec89c56

Revamp the palette handling in lib64gfx somewhat, add helper functions to lib64util for handling external palette file options and add support for specifying one of the "internal" palettes or external (.act) palette file to gfxconv and 64vw.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 14 Jun 2019 05:01:12 +0300
parents e3f0eaf23f4f
children d76b0c92769d
line wrap: on
line source

/*
 * data2inc - Convert binary data to "C"-source or XA-compatible include file
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP)
 *
 * Please read file 'COPYING' for information on license and distribution.
 */
#include "dmtool.h"
#include "dmlib.h"
#include "dmargs.h"
#include "dmmutex.h"


#define RA_LINEBUF    (16)

enum
{
    FMT_AUTO = 0,
    FMT_C,
    FMT_ASM
};

char    *optInFilename = NULL,
        *optOutFilename = NULL,
        *optObjName = "default_object",
        *optDataType = NULL,
        *optAddLine = NULL;

int     optIndentation = -1;
int     optFormat = FMT_AUTO;
BOOL    optHexMode = FALSE,
        optQuiet = FALSE,
        optExtraData = FALSE,
        optFormatting = TRUE;


void (*writeHeader) (FILE *, char *) = NULL;
void (*writeDecl) (FILE *, unsigned int, char *) = NULL;
void (*writeData) (FILE *, Uint8 *, unsigned int) = NULL;
void (*writeFooter) (FILE *, unsigned int, char *) = NULL;


static const DMOptArg optList[] =
{
    {  0, '?', "help",           "Show this help", OPT_NONE },
    {  4, 'A', "format-asm",     "Output in XA-compatible asm", OPT_NONE },
    {  5, 'C', "format-c",       "Output in ANSI C", OPT_NONE },
    {  1, 'n', "name",           "Set object name", OPT_ARGREQ },
    {  2, 't', "type",           "Set datatype (unsigned char/byte)", OPT_ARGREQ },
    {  3, 'a', "add-line",       "Add this line to start of file", OPT_ARGREQ },
    {  6, 'x', "hexadecimal",    "Use hexadecimal output", OPT_NONE },
    {  7, 'q', "quiet",          "Do not add comments", OPT_NONE },
    {  8, 'f', "no-formatting",  "Disable additional output formatting", OPT_NONE },
    {  9, 'i', "indentation",    "Set indentation (negative value = tab)", OPT_ARGREQ },
    { 10, 'e', "extra-data",     "Add object end labels and size in asm output", OPT_NONE },
};

static const int optListN = sizeof(optList) / sizeof(optList[0]);


void argShowHelp()
{
    dmPrintBanner(stdout, dmProgName,
        "[options] [sourcefile] [destfile]");

    dmArgsPrintHelp(stdout, optList, optListN, 0);

    printf(
    "\n"
    "To convert a data file to a C structure using 'Uint8' as type:\n"
    "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n"
    "\n"
    );
}


BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
{
    switch (optN)
    {
        case 0:
            argShowHelp();
            exit(0);
            break;

        case 1:
            optObjName = optArg;
            break;

        case 2:
            optDataType = optArg;
            break;

        case 3:
            optAddLine = optArg;
            break;

        case 4:
            optFormat = FMT_ASM;
            break;
        case 5:
            optFormat = FMT_C;
            break;
        case 6:
            optHexMode = TRUE;
            break;
        case 7:
            optQuiet = TRUE;
            break;
        case 8:
            optFormatting = FALSE;
            break;

        case 9:
            optIndentation = atoi(optArg);
            break;

        case 10:
            optExtraData = TRUE;
            break;

        default:
            dmErrorMsg("Unimplemented option argument '%s'.\n", currArg);
            return FALSE;
    }

    return TRUE;
}


BOOL argHandleFile(char * currArg)
{
    if (!optInFilename)
        optInFilename = currArg;
    else
    if (!optOutFilename)
        optOutFilename = currArg;
    else
        dmErrorMsg("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg);

    return TRUE;
}


/* Assembler include data output functions
 */
void writeHeader_ASM(FILE * f, char *name)
{
    if (name)
        fprintf(f, "; '%s'", name);
    else
        fprintf(f, "; Generated");
    fprintf(f, " by %s v%s\n",
        dmProgName, dmProgVersion);
}

void writeDecl_ASM(FILE * f, unsigned int len, char *name)
{
    if (optExtraData)
        fprintf(f, "%s_size = %u\n", name, len);
    fprintf(f, "%s:\n", name);
}

void writeData_ASM(FILE * f, Uint8 * buf, unsigned int len)
{
    fprintf(f, "%s ", optDataType);
    for (unsigned int i = 0; i < len; i++)
    {
        if (optFormatting)
        {
            if (optHexMode)
                fprintf(f, "$%.2x", buf[i]);
            else
                fprintf(f, "%3d", buf[i]);
        }
        else
        {
            if (optHexMode)
                fprintf(f, "$%x", buf[i]);
            else
                fprintf(f, "%d", buf[i]);
        }

        if (i < len - 1)
            fprintf(f, ",");
    }
}

void writeFooter_ASM(FILE * f, unsigned int len, char *name)
{
    (void) len;
    if (optExtraData)
        fprintf(f, "%s_end: \n", name);
    else
        fprintf(f, "\n");
}


/* ANSI-C include data output functions
 */
void writeHeader_C(FILE * f, char *name)
{
    if (name)
        fprintf(f, "/* '%s' generated", name);
    else
        fprintf(f, "/* Generated");

    fprintf(f, " by %s v%s\n" " */\n",
        dmProgName, dmProgVersion);
}

void writeDecl_C(FILE * f, unsigned int len, char *name)
{
    fprintf(f, "%s %s[%u] = {\n",
        optDataType, name, len);

    printf("extern %s %s[%u];\n",
        optDataType, name, len);
}

void writeData_C(FILE * f, Uint8 * buf, unsigned int len)
{
    unsigned int i;

    for (i = 0; i < len; i++)
    {
        if (optFormatting)
        {
            if (optHexMode)
                fprintf(f, "0x%.2x", buf[i]);
            else
                fprintf(f, "%3d", buf[i]);
        }
        else
        {
            if (optHexMode)
                fprintf(f, "0x%x", buf[i]);
            else
                fprintf(f, "%d", buf[i]);
        }

        fprintf(f, ",");
    }
}

void writeFooter_C(FILE * f, unsigned int len, char *name)
{
    (void) len;
    (void) name;
    fprintf(f, "};\n");
}


off_t dmGetFileSize(FILE *f)
{
    off_t len, pos = ftello(f);
    fseeko(f, 0, SEEK_END);
    len = ftello(f);
    fseeko(f, pos, SEEK_SET);
    return len;
}


int main(int argc, char *argv[])
{
    FILE *sfile = NULL, *dfile = NULL;
    off_t inSize;
    Uint8 inBuf[RA_LINEBUF];
    int tmpRes;

    /* Initialize */
    dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL);
    dmVerbosity = 0;

    /* Parse arguments */
    if (!dmArgsProcess(argc, argv, optList, optListN,
        argHandleOpt, argHandleFile, OPTH_BAILOUT))
        exit(1);

    /* Determine output type, if not specified */
    if (optFormat == FMT_AUTO)
    {
        char *dext;

        if (optOutFilename == NULL)
        {
            dmErrorMsg("Output format not specified and no output filename given (try --help)\n");
            exit(1);
        }

        /* Check filename extension */
        dext = strrchr(optOutFilename, '.');
        if (dext)
        {
            dext++;
            if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") ||
                !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") ||
                !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++"))
                optFormat = FMT_C;
            else
                optFormat = FMT_ASM;
        } else
            optFormat = FMT_ASM;
    }

    /* Set functions */
    switch (optFormat)
    {
        case FMT_ASM:
            if (!optDataType)
                optDataType = ".byte";

            writeHeader = writeHeader_ASM;
            writeDecl = writeDecl_ASM;
            writeData = writeData_ASM;
            writeFooter = writeFooter_ASM;
            break;

        case FMT_C:
            if (!optDataType)
                optDataType = "unsigned char";

            writeHeader = writeHeader_C;
            writeDecl = writeDecl_C;
            writeData = writeData_C;
            writeFooter = writeFooter_C;
            break;

        case FMT_AUTO:
        default:
            dmErrorMsg("Internal error, FMT_AUTO at output function init.\n");
            exit(2);
    }

    /* Open the files */
    if (optInFilename == NULL)
        sfile = stdin;
    else
    if ((sfile = fopen(optInFilename, "rb")) == NULL)
    {
        tmpRes = dmGetErrno();
        dmErrorMsg("Error opening input file '%s'. (%s)\n",
            optInFilename, dmErrorStr(tmpRes));
        exit(3);
    }

    if (optOutFilename == NULL)
        dfile = stdout;
    else
    if ((dfile = fopen(optOutFilename, "wa")) == NULL)
    {
        tmpRes = dmGetErrno();
        dmErrorMsg("Error creating output file '%s'. (%s)\n",
            optOutFilename, dmErrorStr(tmpRes));
        exit(4);
    }

    /* Get sourcefile size */
    inSize = dmGetFileSize(sfile);

    /* Output header */
    if (!optQuiet)
        writeHeader(dfile, optOutFilename);

    if (optAddLine)
        fprintf(dfile, "%s\n", optAddLine);

    /* Output declaration */
    writeDecl(dfile, inSize, optObjName);

    /* Output data */
    while (!feof(sfile))
    {
        tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile);
        if (tmpRes > 0)
        {
            if (optIndentation < 0)
                fprintf(dfile, "\t");
            else
            if (optIndentation > 0)
            {
                int i;
                for (i = 0; i < optIndentation; i++)
                    fputs(" ", dfile);
            }

            writeData(dfile, inBuf, tmpRes);

            fprintf(dfile, "\n");
        }
    }


    /* Output footer */
    writeFooter(dfile, inSize, optObjName);

    /* Exit */
    fclose(sfile);
    fclose(dfile);

    return 0;
}