Mercurial > hg > dmlib
view tools/data2inc.c @ 2343:94a653883a32
Change Uint8 pointer in getPixel functions to DMC64ScanLine pointer in
preparation for future changes related to sprites on scanlines.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Wed, 25 Sep 2019 12:11:35 +0300 |
parents | e771185db600 |
children | b7cd5dd0b82e |
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-2019 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 SET_DEF_LINELEN 16 #define SET_MAX_FEXTS 16 // // Types etc // typedef struct { char *name; char *desc; char *fexts[SET_MAX_FEXTS]; char *defDataType; void (*writeHeader) (FILE *fh, const char *name); void (*writeDecl) (FILE *fh, const size_t len, const char *name); void (*writeData) (FILE *fh, const Uint8 *buf, const size_t len); void (*writeFooter) (FILE *fh, const size_t len, const char *name); } DMOutputFormat; // // Options // char *optInFilename = NULL, *optOutFilename = NULL, *optObjName = "default_object", *optDataType = NULL, *optAddLine = NULL; const DMOutputFormat *setFormat = NULL; int optIndentation = -1, optLineLen = SET_DEF_LINELEN; BOOL optHexMode = FALSE, optQuiet = FALSE, optExtraData = FALSE, optFormatting = TRUE; static const DMOptArg optList[] = { { 0, '?', "help", "Show this help", OPT_NONE }, { 1, 'n', "name", "Set object name", OPT_ARGREQ }, { 2, 't', "type", "Set datatype (unsigned char/byte)", OPT_ARGREQ }, { 3, 'f', "format", "Set output format (see list below)", OPT_ARGREQ }, { 4, 'a', "add-line", "Add this line to start of file", OPT_ARGREQ }, { 5, 'l', "line-items", "Set number of items per line", OPT_ARGREQ }, { 6, 'x', "hexadecimal", "Use hexadecimal output", OPT_NONE }, { 7, 'q', "quiet", "Do not add comments", OPT_NONE }, { 8, 'N', "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]); static const DMOutputFormat dmFormatList[]; static const int ndmFormatList; void argShowHelp() { dmPrintBanner(stdout, dmProgName, "[options] [sourcefile] [destfile]"); dmArgsPrintHelp(stdout, optList, optListN, 0); fprintf(stdout, "\n" "Available output formats (-f <frmt>):\n" " frmt | Description (filename extensions)\n" "------+------------------------------------------\n"); for (int i = 0; i < ndmFormatList; i++) { const DMOutputFormat *fmt = &dmFormatList[i]; fprintf(stdout, "%-5s | %s (", fmt->name, fmt->desc); for (int n = 0; n < SET_MAX_FEXTS && fmt->fexts[n] != NULL; n++) { fprintf(stdout, ".%s%s", fmt->fexts[n], (n + 1 < SET_MAX_FEXTS && fmt->fexts[n + 1] != NULL) ? " " : ""); } fprintf(stdout, ")\n"); } fprintf(stdout, "\n" "To convert a data file to a C structure using 'Uint8' as type:\n" "$ data2inc -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: for (int i = 0; i < ndmFormatList; i++) { const DMOutputFormat *fmt = &dmFormatList[i]; if (strcasecmp(fmt->name, optArg) == 0) { setFormat = fmt; return TRUE; } } dmErrorMsg("Invalid format name '%s'.\n", optArg); return FALSE; case 4: optAddLine = optArg; break; case 5: optLineLen = atoi(optArg); if (optLineLen < 1) { dmErrorMsg("Invalid line length / number of items per line '%s'.\n", optArg); return FALSE; } 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 == NULL) optInFilename = currArg; else if (optOutFilename == NULL) 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 *fh, const char *name) { if (name) fprintf(fh, "; '%s'", name); else fprintf(fh, "; Generated"); fprintf(fh, " by %s v%s\n", dmProgName, dmProgVersion); } void writeDecl_ASM(FILE *fh, const size_t len, const char *name) { if (optExtraData) fprintf(fh, "%s_size = %" DM_PRIu_SIZE_T "\n", name, len); fprintf(fh, "%s:\n", name); } void writeData_ASM(FILE *fh, const Uint8 * buf, const size_t len) { fprintf(fh, "%s ", optDataType); for (size_t i = 0; i < len; i++) { if (optFormatting) { if (optHexMode) fprintf(fh, "$%.2x", buf[i]); else fprintf(fh, "%3d", buf[i]); } else { if (optHexMode) fprintf(fh, "$%x", buf[i]); else fprintf(fh, "%d", buf[i]); } if (i + 1 < len) fprintf(fh, optFormatting ? ", " : ","); } } void writeFooter_ASM(FILE *fh, const size_t len, const char *name) { (void) len; if (optExtraData) fprintf(fh, "%s_end: \n", name); else fprintf(fh, "\n"); } /* ANSI-C include data output functions */ void writeHeader_C(FILE *fh, const char *name) { if (name) fprintf(fh, "/* '%s' generated", name); else fprintf(fh, "/* Generated"); fprintf(fh, " by %s v%s\n" " */\n", dmProgName, dmProgVersion); } void writeDecl_C(FILE *fh, const size_t len, const char *name) { fprintf(fh, "%s %s[%" DM_PRIu_SIZE_T "] = {\n", optDataType, name, len); printf("extern %s %s[%" DM_PRIu_SIZE_T "];\n", optDataType, name, len); } void writeData_C(FILE *fh, const Uint8 *buf, const size_t len) { for (size_t i = 0; i < len; i++) { if (optFormatting) { if (optHexMode) fprintf(fh, "0x%.2x", buf[i]); else fprintf(fh, "%3d", buf[i]); } else { if (optHexMode) fprintf(fh, "0x%x", buf[i]); else fprintf(fh, "%d", buf[i]); } fprintf(fh, optFormatting ? ", " : ","); } } void writeFooter_C(FILE *fh, const size_t len, const char *name) { (void) len; (void) name; fprintf(fh, "};\n"); } static const DMOutputFormat dmFormatList[] = { { "asm", "XA65 compatible assembler", { "s", "asm", NULL }, ".byte", writeHeader_ASM, writeDecl_ASM, writeData_ASM, writeFooter_ASM, }, { "c", "ANSI C array", { "c", "h", "cc", "cpp", "hpp", "c++", NULL }, "unsigned char", writeHeader_C, writeDecl_C, writeData_C, writeFooter_C, }, }; static const int ndmFormatList = sizeof(dmFormatList) / sizeof(dmFormatList[0]); off_t dmGetFileSize(FILE *fh) { off_t len, pos = ftello(fh); fseeko(fh, 0, SEEK_END); len = ftello(fh); fseeko(fh, pos, SEEK_SET); return len; } const DMOutputFormat *dmGuessFormatFromName(const char *filename) { const char *fext; if ((fext = strrchr(filename, '.')) == NULL) return NULL; for (int i = 0; i < ndmFormatList; i++) { const DMOutputFormat *fmt = &dmFormatList[i]; for (int n = 0; n < SET_MAX_FEXTS && fmt->fexts[n] != NULL; n++) { if (strcasecmp(fext + 1, fmt->fexts[n]) == 0) return fmt; } } return NULL; } int main(int argc, char *argv[]) { FILE *inFile = NULL, *outFile = NULL; Uint8 *dataBuf = NULL; size_t dataSize; off_t totalSize; int res; // Initialize dmInitProg("data2inc", "Data to include converter", "0.7", 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 (setFormat == NULL) { if (optOutFilename == NULL) { dmErrorMsg("Output format not specified and no output filename given (try --help)\n"); goto exit; } if ((setFormat = dmGuessFormatFromName(optOutFilename)) == NULL) { dmErrorMsg("Could not guess output format from filename '%s'.\n", optOutFilename); goto exit; } dmMsg(0, "Guessed output format: %s (%s)\n", setFormat->desc, setFormat->name); } // Set some option defaults if (optDataType == NULL) optDataType = setFormat->defDataType; // Open the files if (optInFilename == NULL) inFile = stdin; else if ((inFile = fopen(optInFilename, "rb")) == NULL) { res = dmGetErrno(); dmErrorMsg("Error opening input file '%s'. (%s)\n", optInFilename, dmErrorStr(res)); goto exit; } if (optOutFilename == NULL) outFile = stdout; else if ((outFile = fopen(optOutFilename, "wa")) == NULL) { res = dmGetErrno(); dmErrorMsg("Error creating output file '%s'. (%s)\n", optOutFilename, dmErrorStr(res)); goto exit; } // Allocate linebuffer dataSize = optLineLen * sizeof(Uint8); if ((dataBuf = dmMalloc(dataSize)) == NULL) { dmErrorMsg("Could not allocate %" DM_PRIu_SIZE_T " byte buffer.\n", dataSize); goto exit; } // Get sourcefile size totalSize = dmGetFileSize(inFile); // Output header if (!optQuiet) setFormat->writeHeader(outFile, optOutFilename); if (optAddLine) fprintf(outFile, "%s\n", optAddLine); // Output declaration setFormat->writeDecl(outFile, totalSize, optObjName); // Output data while (!feof(inFile)) { res = fread(dataBuf, 1, dataSize, inFile); if (res > 0) { if (optIndentation < 0) { for (int i = 0; i < -optIndentation; i++) fputs("\t", outFile); } else if (optIndentation > 0) { for (int i = 0; i < optIndentation; i++) fputs(" ", outFile); } setFormat->writeData(outFile, dataBuf, res); fprintf(outFile, "\n"); } } // Output footer setFormat->writeFooter(outFile, totalSize, optObjName); exit: // Cleanup if (inFile != NULL) fclose(inFile); if (outFile != NULL) fclose(outFile); dmFree(dataBuf); return 0; }