diff data2inc.c @ 407:59244a7ae37f

Move c64 utilities to the engine lib, as we benefit from a common framework.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 03 Nov 2012 02:19:51 +0200
parents
children 9d668e48961c
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data2inc.c	Sat Nov 03 02:19:51 2012 +0200
@@ -0,0 +1,404 @@
+/*
+ * 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 <errno.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 *, size_t, char *) = NULL;
+void (*writeData) (FILE *, Uint8 *, size_t) = NULL;
+void (*writeFooter) (FILE *, size_t, char *) = NULL;
+
+
+static 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);
+    
+    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:
+            dmError("Unknown option '%s'.\n", currArg);
+            return FALSE;
+    }
+
+    return TRUE;
+}
+
+
+BOOL argHandleFile(char * currArg)
+{
+    if (!optInFilename)
+        optInFilename = currArg;
+    else
+    if (!optOutFilename)
+        optOutFilename = currArg;
+    else
+        dmError("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, size_t 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, size_t len)
+{
+    size_t i;
+
+    fprintf(f, "%s ", optDataType);
+    for (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, size_t 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, size_t len, char *name)
+{
+    fprintf(f, "const %s %s[%u] = {\n",
+        optDataType, name, len);
+
+    printf("extern const %s %s[%u];\n",
+        optDataType, name, len);
+}
+
+void writeData_C(FILE * f, Uint8 * buf, size_t len)
+{
+    size_t 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, size_t len, char *name)
+{
+    (void) len;
+    (void) name;
+    fprintf(f, "};\n");
+}
+
+
+off_t dmGetFileSize(FILE *f)
+{
+    off_t len, pos = ftell(f);
+    fseeko(f, 0, SEEK_END);
+    len = ftell(f);
+    fseek(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, TRUE))
+        exit(1);
+
+    /* Determine output type, if not specified */
+    if (optFormat == FMT_AUTO)
+    {
+        char *dext;
+
+        if (optOutFilename == NULL)
+        {
+            dmError("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:
+            dmError("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 = errno;
+        dmError("Error opening input file '%s'. (%s)\n",
+            optInFilename, strerror(tmpRes));
+        exit(3);
+    }
+
+    if (optOutFilename == NULL)
+        dfile = stdout;
+    else
+    if ((dfile = fopen(optOutFilename, "wa")) == NULL)
+    {
+        tmpRes = errno;
+        dmError("Error creating output file '%s'. (%s)\n",
+            optOutFilename, strerror(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);
+
+    exit(0);
+    return 0;
+}