10 /* Version information */
11 const char *versionInfo
=
12 "bin2c version 1.0 by Fatih Aygun\n"
14 "Visit sourceforge.net/projects/bin2c to for new versions.\n"
15 "This program is public domain, do whatever you want with it.\n"
18 /* Command line help */
19 const char *commandLineHelp
=
20 "Usage: bin2c [OPTION...] FILE [FILE...]\n"
21 "bin2c creates a C soures and headers from binary files.\n"
24 " bin2c -o foo.h bar.bin # Create 'foo.h' from the contents of\n"
26 " bin2c -o foo.h file1 file2 # Create 'foo.h' from the contents of 'file1'\n"
28 " bin2c -d foo.h -o foo.c bar.bin # Create 'foo.c' and 'foo.h' from the\n"
29 " contents of 'bar.bin'\n"
32 " -d, --header <file name> Name a header file (A header file will not be\n"
33 " created unless explicitly named)\n"
34 " -h, --help Print this command line help and exit immediately\n"
35 " -o, --output <file name> Name an output file\n"
36 " -m, --macro Create the size definition as a macro instead of\n"
38 " -n, --name <symbol name> Name the symbol to be defined\n"
39 " -v, --version Print version information and exit immediately\n"
41 "Visit sourceforge.net/projects/bin2c to for new versions.\n"
42 "This program is public domain, do whatever you want with it.\n"
45 /* Output formatting macros */
46 #define bytesPerLine 16
47 #define indentString " "
48 #define outputFormatBase "0x%.2X"
49 #define outputFormat outputFormatBase", "
50 #define outputFormatEOL outputFormatBase",\n"
51 #define outputFormatEOF outputFormatBase"\n"
52 #define sizeDefinition "const long int bin2c_%s_size = %d;\n"
53 #define sizeMacroDefinition "#define bin2c_%s_size %d\n"
54 #define typeName "const unsigned char"
61 /* Global variables */
62 FILE *outputFile
=0; /* Current output file stream */
63 const char *outputFileName
=0; /* Current output file name */
64 FILE *headerFile
=0; /* Current header file */
65 const char *headerFileName
=0; /* Current header file name */
66 FILE *tmpFuncFile
=0; /* File to write final function that search for files */
67 const char *tmpFuncFileName
=0; /* Current tmpFunc file name */
68 char *symbolName
=0; /* Current symbol name */
69 char *headerSymbol
=0; /* Symbol for multiple inclusion protection */
70 bool createMacro
= false; /* Should we create a define instead of a const? */
73 const char* cantOpen
= "Can't open file '%s'";
74 const char* cantClose
= "Can't close file '%s'";
75 const char* cantRemove
= "Can't remove file '%s'";
76 const char* cantWrite
= "Can't write to file '%s'";
77 const char* noOutputFilesAreNamed
= "No output files are named";
78 const char* noHeaderFilesAreNamed
= "No header files are named";
79 const char* cantMalloc
= "Can't allocate memory for '%s'";
80 const char* cantSeek
= "Can't seek in the file '%s'";
81 const char* cantDetermine
= "Can't determine the file size of '%s'";
82 const char* cantRead
= "Can't read from file %s";
83 const char* unknownOption
= "Unknown option '%s'";
84 const char* tryHelp
= "Try 'bin2c --help' for more information.\n";
85 const char* noSymbolName
= "No symbol name is given";
86 const char* notValidId
= "'%s' is not a valid identifier";
87 const char* symbolNameGiven
= "Symbol name is given twice";
89 /* Print a formatted error message */
90 static void vprintfError(const char *format
, va_list args
)
92 fprintf(stderr
, "bin2c: ");
93 vfprintf(stderr
, format
, args
);
95 fprintf(stderr
, ": ");
99 fprintf(stderr
, "\n");
103 static void printfError(const char *format
, ...)
107 va_start(args
, format
);
108 vprintfError(format
, args
);
115 /* Close and remove the output file if it's open */
117 if (fclose(outputFile
)) {
118 printfError(cantClose
, outputFileName
);
121 if (remove(outputFileName
)) {
122 printfError(cantRemove
, outputFileName
);
126 /* Close and remove the header file if it's open */
128 if (fclose(headerFile
)) {
129 printfError(cantClose
, headerFileName
);
132 if (remove(headerFileName
)) {
133 printfError(cantRemove
, headerFileName
);
137 /* Close and remove the header file if it's open */
139 if (fclose(tmpFuncFile
)) {
140 printfError(cantClose
, tmpFuncFileName
);
143 if (remove(tmpFuncFileName
)) {
144 printfError(cantRemove
, tmpFuncFileName
);
148 /* Exit with an error code */
152 /* Check a contidion and panic if it's false */
153 static void check(bool condition
, const char *format
, ...)
158 va_start(args
, format
);
159 vprintfError(format
, args
);
165 /* Write a formatted string to the output file and check for errors */
166 static void output(const char *format
, ...)
170 /* Try to write to the file */
171 va_start(args
, format
);
172 vfprintf(outputFile
, format
, args
);
175 /* Check for errors */
176 check(!ferror(outputFile
), cantWrite
, outputFileName
);
179 /* Write a formatted string to the header file and check for errors */
180 static void header(const char *format
, ...)
184 /* Try to write to the file */
185 va_start(args
, format
);
186 vfprintf(headerFile
, format
, args
);
189 /* Check for errors */
190 check(!ferror(headerFile
), cantWrite
, headerFileName
);
193 /* Write a formatted string to the tmp file and check for errors */
194 static void tmpFunc(const char *format
, ...)
198 /* Try to write to the file */
199 va_start(args
, format
);
200 vfprintf(tmpFuncFile
, format
, args
);
203 /* Check for errors */
204 check(!ferror(tmpFuncFile
), cantWrite
, tmpFuncFileName
);
207 /* Allocate a valid C identifier from a file name */
208 static char *fileNameToSymbol(const char *fileName
)
213 name
= malloc(strlen(fileName
) + 1);
214 check(name
!= 0, cantMalloc
, "the symbol name");
216 /* Copy the file name to symbolName */
217 strcpy(name
, fileName
);
219 /* Replace every non alphanumerical character with '_' */
220 for (i
= 0; name
[i
]; ++i
) {
221 if (!((name
[i
] >= 'a' && name
[i
] <= 'z') ||
222 (name
[i
] >= 'A' && name
[i
] <= 'Z') ||
223 (name
[i
] >= '0' && name
[i
] <= '9'))) {
228 /* Replace the first character with '_' if it's a digit */
229 if (name
[0] >= '0' && name
[0] <= '9') {
236 int isdir(const char * path
)
241 if (path
== NULL
) return 0;
242 if (stat(path
, &buf
) == 0 && S_ISDIR(buf
.st_mode
)) bOK
=1;
244 wchar_t *wcpath
= to_wide_string((char*)path
);
245 if (wcpath
== NULL
) return FALSE
;
246 bOK
= isdirW(wcpath
);
252 /* Process an input file */
253 static int processFile(const char *fileName
, long int from
, long int to
)
255 bool symbolNameAllocated
= false; /* Did we allocate the symbolName? */
256 long int i
, j
; /* Indexes for various purposes */
257 FILE *inputFile
; /* Input file stream */
258 int byte
; /* Byte read from the input */
261 if(isdir(fileName
)) return 0;
263 /* Be sure that the output file is open */
264 check(outputFile
!= 0, noOutputFilesAreNamed
);
266 /* Write the comment */
267 output("\n/* Contents of file %s */\n", fileName
);
269 header("\n/* Contents of file %s */\n", fileName
);
272 /* Make up a suitable symbolName if we don't have one */
274 symbolName
= fileNameToSymbol(fileName
);
275 symbolNameAllocated
= true;
278 /* Open the input file */
279 inputFile
= fopen(fileName
, "rb");
280 check(inputFile
!= 0, cantOpen
, fileName
);
282 /* If to == -1, set it to the last byte of the file */
284 check(!fseek(inputFile
, 0, SEEK_END
), cantSeek
, fileName
);
285 to
= ftell(inputFile
);
286 check(to
>= 0, cantDetermine
, fileName
);
290 assert(from
<= to
- 1);
292 /* Position the file to "from" */
293 check(!fseek(inputFile
, from
, SEEK_SET
), cantSeek
, fileName
);
295 fsize
= to
- from
+ 1;
297 /* Output the size definition */
300 header(sizeMacroDefinition
, symbolName
, fsize
);
302 header("extern "sizeDefinition
, symbolName
, fsize
);
303 output(sizeDefinition
, symbolName
, fsize
);
307 output(sizeMacroDefinition
, symbolName
, fsize
);
309 output(sizeDefinition
, symbolName
, fsize
);
314 tmpFunc("\t{\"/_attach_/%s\", bin2c_%s, %d},\n", fileName
, symbolName
, fsize
);
316 /* Output the definition */
317 output("%s bin2c_%s[%d] = {\n", typeName
, symbolName
, fsize
);
319 header("extern %s *bin2c_%s;\n", typeName
, symbolName
, fsize
);
322 /* Output the contents */
324 for (i
= from
; i
<= to
; ++i
) {
325 /* Read a byte from the input file */
326 byte
= fgetc(inputFile
);
327 check(byte
!= EOF
, cantRead
, fileName
);
329 /* Output the indentation if it's the first byte of a line */
331 output(indentString
);
334 /* Output the actual byte */
336 /* Output the last byte */
337 output(outputFormatEOF
, byte
);
338 } else if (j
== bytesPerLine
) {
339 /* Output the last byte of a line */
340 output(outputFormatEOL
, byte
);
342 /* Output a normal byte */
343 output(outputFormat
, byte
);
348 if (j
> bytesPerLine
) {
353 /* Output the end of definition */
356 /* Free the symbol name if it was allocated by us */
357 if (symbolNameAllocated
) {
361 /* Clear the symbol name */
366 /* Unknown option error */
367 static void handleUnknownOption(const char *s
)
369 printfError(unknownOption
, s
);
370 fprintf(stderr
, tryHelp
);
374 /* Open an output file */
375 static void openOutputFile(const char *fileName
)
377 /* Be sure that a file name is given */
379 printfError(noOutputFilesAreNamed
);
380 fprintf(stderr
, tryHelp
);
384 /* Close previous output file if any */
386 check(!fclose(outputFile
), cantClose
, outputFileName
);
389 /* Open the new output file */
390 outputFile
= fopen(fileName
, "w");
391 check(outputFile
!= 0, cantOpen
, outputFileName
);
392 outputFileName
= fileName
;
394 output("/* Generated by bin2c, do not edit manually */\n");
397 /* Open a header file */
398 static void openHeaderFile(const char *fileName
)
400 /* Be sure that a file name is given */
402 printfError(noHeaderFilesAreNamed
);
403 fprintf(stderr
, tryHelp
);
407 /* Close previous header file if any */
409 header("\n#endif /* __%s_included */\n", headerSymbol
);
412 check(!fclose(headerFile
), cantClose
, headerFileName
);
415 /* Open the new header file */
416 headerFile
= fopen(fileName
, "w");
417 check(headerFile
!= 0, cantOpen
, headerFileName
);
418 headerFileName
= fileName
;
419 headerSymbol
= fileNameToSymbol(fileName
);
421 header("/* Generated by bin2c, do not edit manually */\n");
422 header("#ifndef __%s_included\n", headerSymbol
);
423 header("#define __%s_included\n", headerSymbol
);
426 typedef void writeFileFunc(const char *format
, ...);
428 void writeAttchmentStruct(writeFileFunc
*writeFunc
){
429 (*writeFunc
)("\ntypedef struct {\n");
430 (*writeFunc
)("\tconst char *file_name;\n");
431 (*writeFunc
)("\tconst unsigned char *sym_name;\n");
432 (*writeFunc
)("\tlong size;\n");
433 (*writeFunc
)("} bin2c_filesAttached_st;\n");
436 /* Open a header file */
437 static void openFuncFile(const char *fileName
)
439 static char fnBuf
[1024];
440 /* Be sure that a file name is given */
442 printfError(noHeaderFilesAreNamed
);
443 fprintf(stderr
, tryHelp
);
447 /* Close previous header file if any */
450 check(!fclose(tmpFuncFile
), cantClose
, tmpFuncFileName
);
453 snprintf(fnBuf
, sizeof(fnBuf
), "%s.tmp", fileName
);
455 /* Open the new header file */
456 tmpFuncFile
= fopen(fnBuf
, "w");
457 check(tmpFuncFile
!= 0, cantOpen
, fnBuf
);
458 tmpFuncFileName
= fnBuf
;
460 tmpFunc("\n/* Generated by bin2c, do not edit manually */\n");
461 writeAttchmentStruct(&tmpFunc
);
462 tmpFunc("const bin2c_filesAttached_st bin2c_filesAttached[] = {\n");
465 /* Set the symbol name for next file */
466 static void setSymbolName(char *name
)
471 printfError(symbolNameGiven
);
472 fprintf(stderr
, tryHelp
);
476 /* Be sure that a symbol name is given */
478 printfError(noSymbolName
);
479 fprintf(stderr
, tryHelp
);
483 /* Check if the symbol is a valid C identifier */
484 check((name
[0] >= 'a' && name
[0] <='z') ||
485 (name
[0] >= 'A' && name
[0] <='Z') ||
486 (name
[0] == '_'), notValidId
, name
);
488 for (i
= 1; name
[i
]; ++i
) {
489 check((name
[i
] >= 'a' && name
[i
] <='z') ||
490 (name
[i
] >= 'A' && name
[i
] <='Z') ||
491 (name
[i
] >= '0' && name
[i
] <='9') ||
492 (name
[i
] == '_'), notValidId
, name
);
495 /* Set the symbol name */
499 void concatenate(const char *dest
, const char *src
){
501 FILE *fpdest
=fopen(dest
,"a");
502 FILE *fpsrc
=fopen(src
,"r");
503 while((ch
=getc(fpsrc
))!=EOF
) putc(ch
,fpdest
);
507 int main(int argc
, char **argv
)
509 int i
; /* Index to process commandline arguments */
510 int ipf
= 0; /*total files processed*/
512 /* Scan for a -h or --help option */
513 for (i
= 1; i
< argc
; ++i
) {
514 if (!strcmp(argv
[i
], "-h") || !strcmp(argv
[i
], "--help")) {
515 /* Print command line arguments help and exit immediately */
516 printf("%s", commandLineHelp
);
521 /* Scan for a -v or --version option */
522 for (i
= 1; i
< argc
; ++i
) {
523 if (!strcmp(argv
[i
], "-v") || !strcmp(argv
[i
], "--version")) {
524 /* Print version information and exit immediately */
525 printf("%s", versionInfo
);
530 /* Process command line arguments */
531 for (i
= 1; i
< argc
; ++i
) {
532 /* Check if it's an option or file name */
533 if (argv
[i
][0] == '-') {
534 /* Process the option */
535 switch (argv
[i
][1]) {
538 if (!strcmp(argv
[i
], "--output")) {
539 /* Name an output file */
540 openOutputFile(argv
[i
+1]);
541 openFuncFile(argv
[i
+1]);
543 } else if (!strcmp(argv
[i
], "--header")) {
544 /* Name a header file */
545 openHeaderFile(argv
[i
+1]);
547 } else if (!strcmp(argv
[i
], "--macro")) {
548 /* Create a macro for the size definition */
550 } else if (!strcmp(argv
[i
], "--name")) {
551 /* Name the symbol */
552 setSymbolName(argv
[i
+1]);
556 handleUnknownOption(argv
[i
]);
560 /* Name an output file */
561 openOutputFile(argv
[i
+1]);
562 openFuncFile(argv
[i
+1]);
566 /* Name a header file */
567 openHeaderFile(argv
[i
+1]);
571 /* Create a macro for the size definition */
575 /* Name the symbol */
576 setSymbolName(argv
[i
+1]);
581 handleUnknownOption(argv
[i
]);
584 /* Process the file */
585 if(processFile(argv
[i
], 0, -1)) ipf
++;
589 /* Close any remaining output files */
591 writeAttchmentStruct(&header
);
592 header("extern const bin2c_filesAttached_st bin2c_filesAttached[%d];\n", ipf
);
594 header("\n#endif /* __%s_included */\n", headerSymbol
);
597 check(!fclose(headerFile
), cantClose
, headerFileName
);
602 check(!fclose(tmpFuncFile
), cantClose
, tmpFuncFileName
);
606 check(!fclose(outputFile
), cantClose
, outputFileName
);
609 if (tmpFuncFile
&& outputFile
) {
610 concatenate(outputFileName
, tmpFuncFileName
);
611 remove(tmpFuncFileName
);