Mercurial > hg > dmlib
view data2inc.c @ 510:43ea59887c69
Start work on making C64 formats encoding possible by changing DMDecodeOps
to DMEncDecOps and adding fields and op enums for custom encode functions, renaming,
etc. Split generic op sanity checking into a separate function in
preparation for its use in generic encoding function.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 19 Nov 2012 15:06:01 +0200 |
parents | 59244a7ae37f |
children | 9d668e48961c |
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 <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; }