#include #include #include #include #include #include #include /* Version information */ const char *versionInfo = "bin2c version 1.0 by Fatih Aygun\n" "\n" "Visit sourceforge.net/projects/bin2c to for new versions.\n" "This program is public domain, do whatever you want with it.\n" ; /* Command line help */ const char *commandLineHelp = "Usage: bin2c [OPTION...] FILE [FILE...]\n" "bin2c creates a C soures and headers from binary files.\n" "\n" "Examples:\n" " bin2c -o foo.h bar.bin # Create 'foo.h' from the contents of\n" " 'bar.bin'\n" " bin2c -o foo.h file1 file2 # Create 'foo.h' from the contents of 'file1'\n" " and 'file2'\n" " bin2c -d foo.h -o foo.c bar.bin # Create 'foo.c' and 'foo.h' from the\n" " contents of 'bar.bin'\n" "\n" "Options:\n" " -d, --header Name a header file (A header file will not be\n" " created unless explicitly named)\n" " -h, --help Print this command line help and exit immediately\n" " -o, --output Name an output file\n" " -m, --macro Create the size definition as a macro instead of\n" " a const\n" " -n, --name Name the symbol to be defined\n" " -v, --version Print version information and exit immediately\n" "\n" "Visit sourceforge.net/projects/bin2c to for new versions.\n" "This program is public domain, do whatever you want with it.\n" ; /* Output formatting macros */ #define bytesPerLine 16 #define indentString " " #define outputFormatBase "0x%.2X" #define outputFormat outputFormatBase", " #define outputFormatEOL outputFormatBase",\n" #define outputFormatEOF outputFormatBase"\n" #define sizeDefinition "const long int bin2c_%s_size = %d;\n" #define sizeMacroDefinition "#define bin2c_%s_size %d\n" #define typeName "const unsigned char" /* Define bool */ #define bool int #define false 0 #define true 1 /* Global variables */ FILE *outputFile=0; /* Current output file stream */ const char *outputFileName=0; /* Current output file name */ FILE *headerFile=0; /* Current header file */ const char *headerFileName=0; /* Current header file name */ FILE *tmpFuncFile=0; /* File to write final function that search for files */ const char *tmpFuncFileName=0; /* Current tmpFunc file name */ char *symbolName=0; /* Current symbol name */ char *headerSymbol=0; /* Symbol for multiple inclusion protection */ bool createMacro = false; /* Should we create a define instead of a const? */ /* Error messages */ const char* cantOpen = "Can't open file '%s'"; const char* cantClose = "Can't close file '%s'"; const char* cantRemove = "Can't remove file '%s'"; const char* cantWrite = "Can't write to file '%s'"; const char* noOutputFilesAreNamed = "No output files are named"; const char* noHeaderFilesAreNamed = "No header files are named"; const char* cantMalloc = "Can't allocate memory for '%s'"; const char* cantSeek = "Can't seek in the file '%s'"; const char* cantDetermine = "Can't determine the file size of '%s'"; const char* cantRead = "Can't read from file %s"; const char* unknownOption = "Unknown option '%s'"; const char* tryHelp = "Try 'bin2c --help' for more information.\n"; const char* noSymbolName = "No symbol name is given"; const char* notValidId = "'%s' is not a valid identifier"; const char* symbolNameGiven = "Symbol name is given twice"; /* Print a formatted error message */ static void vprintfError(const char *format, va_list args) { fprintf(stderr, "bin2c: "); vfprintf(stderr, format, args); if (errno) { fprintf(stderr, ": "); perror(""); errno = 0; } else { fprintf(stderr, "\n"); } } static void printfError(const char *format, ...) { va_list args; va_start(args, format); vprintfError(format, args); va_end(args); } /* Panic */ static void panic() { /* Close and remove the output file if it's open */ if (outputFile) { if (fclose(outputFile)) { printfError(cantClose, outputFileName); } if (remove(outputFileName)) { printfError(cantRemove, outputFileName); } } /* Close and remove the header file if it's open */ if (headerFile) { if (fclose(headerFile)) { printfError(cantClose, headerFileName); } if (remove(headerFileName)) { printfError(cantRemove, headerFileName); } } /* Close and remove the header file if it's open */ if (tmpFuncFile) { if (fclose(tmpFuncFile)) { printfError(cantClose, tmpFuncFileName); } if (remove(tmpFuncFileName)) { printfError(cantRemove, tmpFuncFileName); } } /* Exit with an error code */ exit(EXIT_FAILURE); } /* Check a contidion and panic if it's false */ static void check(bool condition, const char *format, ...) { va_list args; if (!condition) { va_start(args, format); vprintfError(format, args); va_end(args); panic(); } } /* Write a formatted string to the output file and check for errors */ static void output(const char *format, ...) { va_list args; /* Try to write to the file */ va_start(args, format); vfprintf(outputFile, format, args); va_end(args); /* Check for errors */ check(!ferror(outputFile), cantWrite, outputFileName); } /* Write a formatted string to the header file and check for errors */ static void header(const char *format, ...) { va_list args; /* Try to write to the file */ va_start(args, format); vfprintf(headerFile, format, args); va_end(args); /* Check for errors */ check(!ferror(headerFile), cantWrite, headerFileName); } /* Write a formatted string to the tmp file and check for errors */ static void tmpFunc(const char *format, ...) { va_list args; /* Try to write to the file */ va_start(args, format); vfprintf(tmpFuncFile, format, args); va_end(args); /* Check for errors */ check(!ferror(tmpFuncFile), cantWrite, tmpFuncFileName); } /* Allocate a valid C identifier from a file name */ static char *fileNameToSymbol(const char *fileName) { char *name; int i; name = malloc(strlen(fileName) + 1); check(name != 0, cantMalloc, "the symbol name"); /* Copy the file name to symbolName */ strcpy(name, fileName); /* Replace every non alphanumerical character with '_' */ for (i = 0; name[i]; ++i) { if (!((name[i] >= 'a' && name[i] <= 'z') || (name[i] >= 'A' && name[i] <= 'Z') || (name[i] >= '0' && name[i] <= '9'))) { name[i] = '_'; } } /* Replace the first character with '_' if it's a digit */ if (name[0] >= '0' && name[0] <= '9') { name[0] = '_'; } return name; } int isdir(const char * path) { int bOK = 0; #ifndef _MSC_VER struct stat buf; if (path == NULL) return 0; if (stat(path, &buf) == 0 && S_ISDIR(buf.st_mode)) bOK=1; #else wchar_t *wcpath = to_wide_string((char*)path); if (wcpath == NULL) return FALSE; bOK = isdirW(wcpath); FREE(wcpath); #endif return bOK; } /* Process an input file */ static int processFile(const char *fileName, long int from, long int to) { bool symbolNameAllocated = false; /* Did we allocate the symbolName? */ long int i, j; /* Indexes for various purposes */ FILE *inputFile; /* Input file stream */ int byte; /* Byte read from the input */ long int fsize=0; if(isdir(fileName)) return 0; /* Be sure that the output file is open */ check(outputFile != 0, noOutputFilesAreNamed); /* Write the comment */ output("\n/* Contents of file %s */\n", fileName); if (headerFile) { header("\n/* Contents of file %s */\n", fileName); } /* Make up a suitable symbolName if we don't have one */ if (!symbolName) { symbolName = fileNameToSymbol(fileName); symbolNameAllocated = true; } /* Open the input file */ inputFile = fopen(fileName, "rb"); check(inputFile != 0, cantOpen, fileName); /* If to == -1, set it to the last byte of the file */ if (to == -1) { check(!fseek(inputFile, 0, SEEK_END), cantSeek, fileName); to = ftell(inputFile); check(to >= 0, cantDetermine, fileName); --to; } assert(from <= to - 1); /* Position the file to "from" */ check(!fseek(inputFile, from, SEEK_SET), cantSeek, fileName); fsize = to - from + 1; /* Output the size definition */ if (headerFile) { if (createMacro) { header(sizeMacroDefinition, symbolName, fsize); } else { header("extern "sizeDefinition, symbolName, fsize); output(sizeDefinition, symbolName, fsize); } } else { if (createMacro) { output(sizeMacroDefinition, symbolName, fsize); } else { output(sizeDefinition, symbolName, fsize); } } if (tmpFuncFile) { tmpFunc("\t{\"/_attach_/%s\", bin2c_%s, %d},\n", fileName, symbolName, fsize); } /* Output the definition */ output("%s bin2c_%s[%d] = {\n", typeName, symbolName, fsize); if (headerFile) { header("extern %s *bin2c_%s;\n", typeName, symbolName, fsize); } /* Output the contents */ j = 1; for (i = from; i <= to; ++i) { /* Read a byte from the input file */ byte = fgetc(inputFile); check(byte != EOF, cantRead, fileName); /* Output the indentation if it's the first byte of a line */ if (j == 1) { output(indentString); } /* Output the actual byte */ if (i == to) { /* Output the last byte */ output(outputFormatEOF, byte); } else if (j == bytesPerLine) { /* Output the last byte of a line */ output(outputFormatEOL, byte); } else { /* Output a normal byte */ output(outputFormat, byte); } /* Next byte */ ++j; if (j > bytesPerLine) { j = 1; } } /* Output the end of definition */ output("};\n"); /* Free the symbol name if it was allocated by us */ if (symbolNameAllocated) { free(symbolName); } /* Clear the symbol name */ symbolName = 0; return 1; } /* Unknown option error */ static void handleUnknownOption(const char *s) { printfError(unknownOption, s); fprintf(stderr, tryHelp); panic(); } /* Open an output file */ static void openOutputFile(const char *fileName) { /* Be sure that a file name is given */ if (!fileName) { printfError(noOutputFilesAreNamed); fprintf(stderr, tryHelp); panic(); } /* Close previous output file if any */ if (outputFile) { check(!fclose(outputFile), cantClose, outputFileName); } /* Open the new output file */ outputFile = fopen(fileName, "w"); check(outputFile != 0, cantOpen, outputFileName); outputFileName = fileName; output("/* Generated by bin2c, do not edit manually */\n"); } /* Open a header file */ static void openHeaderFile(const char *fileName) { /* Be sure that a file name is given */ if (!fileName) { printfError(noHeaderFilesAreNamed); fprintf(stderr, tryHelp); panic(); } /* Close previous header file if any */ if (headerFile) { header("\n#endif /* __%s_included */\n", headerSymbol); free(headerSymbol); headerSymbol = 0; check(!fclose(headerFile), cantClose, headerFileName); } /* Open the new header file */ headerFile = fopen(fileName, "w"); check(headerFile != 0, cantOpen, headerFileName); headerFileName = fileName; headerSymbol = fileNameToSymbol(fileName); header("/* Generated by bin2c, do not edit manually */\n"); header("#ifndef __%s_included\n", headerSymbol); header("#define __%s_included\n", headerSymbol); } typedef void writeFileFunc(const char *format, ...); void writeAttchmentStruct(writeFileFunc *writeFunc){ (*writeFunc)("\ntypedef struct {\n"); (*writeFunc)("\tconst char *file_name;\n"); (*writeFunc)("\tconst unsigned char *sym_name;\n"); (*writeFunc)("\tlong size;\n"); (*writeFunc)("} bin2c_filesAttached_st;\n"); } /* Open a header file */ static void openFuncFile(const char *fileName) { static char fnBuf[1024]; /* Be sure that a file name is given */ if (!fileName) { printfError(noHeaderFilesAreNamed); fprintf(stderr, tryHelp); panic(); } /* Close previous header file if any */ if (tmpFuncFile) { tmpFunc("\n};\n"); check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName); } snprintf(fnBuf, sizeof(fnBuf), "%s.tmp", fileName); /* Open the new header file */ tmpFuncFile = fopen(fnBuf, "w"); check(tmpFuncFile != 0, cantOpen, fnBuf); tmpFuncFileName = fnBuf; tmpFunc("\n/* Generated by bin2c, do not edit manually */\n"); writeAttchmentStruct(&tmpFunc); tmpFunc("const bin2c_filesAttached_st bin2c_filesAttached[] = {\n"); } /* Set the symbol name for next file */ static void setSymbolName(char *name) { int i; if (symbolName) { printfError(symbolNameGiven); fprintf(stderr, tryHelp); panic(); } /* Be sure that a symbol name is given */ if (!name) { printfError(noSymbolName); fprintf(stderr, tryHelp); panic(); } /* Check if the symbol is a valid C identifier */ check((name[0] >= 'a' && name[0] <='z') || (name[0] >= 'A' && name[0] <='Z') || (name[0] == '_'), notValidId, name); for (i = 1; name[i]; ++i) { check((name[i] >= 'a' && name[i] <='z') || (name[i] >= 'A' && name[i] <='Z') || (name[i] >= '0' && name[i] <='9') || (name[i] == '_'), notValidId, name); } /* Set the symbol name */ symbolName = name; } void concatenate(const char *dest, const char *src){ int i,ch; FILE *fpdest=fopen(dest,"a"); FILE *fpsrc=fopen(src,"r"); while((ch=getc(fpsrc))!=EOF) putc(ch,fpdest); } /* Main function */ int main(int argc, char **argv) { int i; /* Index to process commandline arguments */ int ipf = 0; /*total files processed*/ /* Scan for a -h or --help option */ for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-h") || !strcmp(argv[i], "--help")) { /* Print command line arguments help and exit immediately */ printf("%s", commandLineHelp); return EXIT_SUCCESS; } } /* Scan for a -v or --version option */ for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-v") || !strcmp(argv[i], "--version")) { /* Print version information and exit immediately */ printf("%s", versionInfo); return EXIT_SUCCESS; } } /* Process command line arguments */ for (i = 1; i < argc; ++i) { /* Check if it's an option or file name */ if (argv[i][0] == '-') { /* Process the option */ switch (argv[i][1]) { case '-': /* Long options */ if (!strcmp(argv[i], "--output")) { /* Name an output file */ openOutputFile(argv[i+1]); openFuncFile(argv[i+1]); ++i; } else if (!strcmp(argv[i], "--header")) { /* Name a header file */ openHeaderFile(argv[i+1]); ++i; } else if (!strcmp(argv[i], "--macro")) { /* Create a macro for the size definition */ createMacro = true; } else if (!strcmp(argv[i], "--name")) { /* Name the symbol */ setSymbolName(argv[i+1]); ++i; } else { /* Unknown option */ handleUnknownOption(argv[i]); } break; case 'o': /* Name an output file */ openOutputFile(argv[i+1]); openFuncFile(argv[i+1]); ++i; break; case 'd': /* Name a header file */ openHeaderFile(argv[i+1]); ++i; break; case 'm': /* Create a macro for the size definition */ createMacro = true; break; case 'n': /* Name the symbol */ setSymbolName(argv[i+1]); ++i; break; default: /* Unknown option */ handleUnknownOption(argv[i]); } } else { /* Process the file */ if(processFile(argv[i], 0, -1)) ipf++; } } /* Close any remaining output files */ if (headerFile) { writeAttchmentStruct(&header); header("extern const bin2c_filesAttached_st bin2c_filesAttached[%d];\n", ipf); header("\n#endif /* __%s_included */\n", headerSymbol); free(headerSymbol); headerSymbol = 0; check(!fclose(headerFile), cantClose, headerFileName); } if (tmpFuncFile) { tmpFunc("};\n"); check(!fclose(tmpFuncFile), cantClose, tmpFuncFileName); } if (outputFile) { check(!fclose(outputFile), cantClose, outputFileName); } if (tmpFuncFile && outputFile) { concatenate(outputFileName, tmpFuncFileName); remove(tmpFuncFileName); } return EXIT_SUCCESS; }