// bin2c.c // // convert a binary file into a C source vector // // THE "BEER-WARE LICENSE" (Revision 3.1415): // sandro AT sigala DOT it wrote this file. As long as you retain this notice you can do // whatever you want with this stuff. If we meet some day, and you think this stuff is // worth it, you can buy me a beer in return. Sandro Sigala #include #include #include #include #include #include #include #include #include #include #ifndef PATH_MAX #define PATH_MAX 1024 #endif const char *name = NULL; static const char *HEADER_FMT = "#ifndef bin2c_%s_h\n" "#define bin2c_%s_h\n" "\n" "#include \"bin2c.hh\"\n" "\n" "extern struct bin_src_file %s%s;\n" "\n" "#endif\n" "\n"; struct file_meta { const char *fm_name; unsigned int fm_compressed_size; unsigned int fm_size; }; void symname(char *dst, const char *fname) { strcpy(dst, fname); for (int lpc = 0; dst[lpc]; lpc++) { if (!isalnum(dst[lpc])) { dst[lpc] = '_'; } } } void process(struct file_meta *fm, FILE *ofile) { struct stat st; if (stat(fm->fm_name, &st) == -1) { perror("unable to stat file"); exit(1); } unsigned char *buf = malloc(st.st_size); unsigned char *dest = malloc(st.st_size); int fd = open(fm->fm_name, O_RDONLY); if (fd == -1) { perror("unable to open file"); exit(1); } int rc; while ((rc = read(fd, &buf[fm->fm_size], (st.st_size - fm->fm_size))) > 0) { fm->fm_size += rc; } uLongf destLen = st.st_size; compress(dest, &destLen, buf, st.st_size); fm->fm_compressed_size = destLen; int c, col = 1; char sym[1024]; symname(sym, basename((char *) fm->fm_name)); fprintf(ofile, "static const unsigned char %s_data[] = {\n", sym); for (int lpc = 0; lpc < destLen; lpc++) { c = dest[lpc]; if (col >= 78 - 6) { fputc('\n', ofile); col = 1; } fprintf(ofile, "0x%.2x, ", c); col += 6; } fprintf(ofile, "0x00\n"); fprintf(ofile, "\n};\n"); free(buf); free(dest); } void usage() { fprintf(stderr, "usage: bin2c [-n name] [input_file1 ...]\n"); exit(1); } int main(int argc, char **argv) { int c; while ((c = getopt(argc, argv, "hn:")) != -1) { switch (c) { case 'n': name = optarg; break; default: usage(); break; } } argc -= optind; argv += optind; if (argc < 1) { usage(); } const char *out_base_name = argv[0]; char hname[PATH_MAX], cname[PATH_MAX]; argc -= 1; argv += 1; snprintf(hname, sizeof(hname), "%s.h", out_base_name); FILE *hfile = fopen(hname, "wb"); if (hfile == NULL) { fprintf(stderr, "cannot open %s for writing\n", hname); exit(1); } snprintf(cname, sizeof(cname), "%s.cc", out_base_name); FILE *cfile = fopen(cname, "wb"); if (cfile == NULL) { fprintf(stderr, "cannot open %s for writing\n", cname); exit(1); } char sym[1024]; if (name) { strcpy(sym, name); } else { const char *in_base = basename(argv[0]); symname(sym, in_base); } int array = argc > 1 || name; char trailer[16]; if (array) { snprintf(trailer, sizeof(trailer), "[%d]", argc); } else { trailer[0] = '\0'; } fprintf(hfile, HEADER_FMT, sym, sym, sym, trailer); fclose(hfile); fprintf(cfile, "#include \"bin2c.hh\"\n"); fprintf(cfile, "\n"); struct file_meta *meta = alloca(sizeof(struct file_meta) * argc); memset(meta, 0, sizeof(struct file_meta) * argc); for (int lpc = 0; lpc < argc; lpc++) { meta[lpc].fm_name = argv[lpc]; process(&meta[lpc], cfile); } fprintf(cfile, "struct bin_src_file %s%s = {\n", sym, trailer); for (int lpc = 0; lpc < argc; lpc++) { char sym[1024]; symname(sym, basename((char *) meta[lpc].fm_name)); fprintf(cfile, " "); if (array) { fprintf(cfile, "{ "); } fprintf(cfile, "\"%s\", %s_data, %d, %d", basename((char *) meta[lpc].fm_name), sym, meta[lpc].fm_compressed_size, meta[lpc].fm_size); if (array) { fprintf(cfile, " },"); } fprintf(cfile, "\n"); } fprintf(cfile, "};\n"); fclose(cfile); return 0; }