incbin.c 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #ifdef _MSC_VER
  2. # define _CRT_SECURE_NO_WARNINGS
  3. #endif
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include <limits.h>
  9. #ifndef PATH_MAX
  10. # define PATH_MAX MAX_PATH
  11. #endif
  12. #define SEARCH_PATHS_MAX 64
  13. #define FILE_PATHS_MAX 1024
  14. static int fline(char **line, size_t *n, FILE *fp) {
  15. int chr;
  16. char *pos;
  17. if (!line || !n || !fp)
  18. return -1;
  19. if (!*line)
  20. if (!(*line = (char *)malloc((*n=64))))
  21. return -1;
  22. chr = *n;
  23. pos = *line;
  24. for (;;) {
  25. int c = fgetc(fp);
  26. if (chr < 2) {
  27. *n += (*n > 16) ? *n : 64;
  28. chr = *n + *line - pos;
  29. if (!(*line = (char *)realloc(*line,*n)))
  30. return -1;
  31. pos = *n - chr + *line;
  32. }
  33. if (ferror(fp))
  34. return -1;
  35. if (c == EOF) {
  36. if (pos == *line)
  37. return -1;
  38. else
  39. break;
  40. }
  41. *pos++ = c;
  42. chr--;
  43. if (c == '\n')
  44. break;
  45. }
  46. *pos = '\0';
  47. return pos - *line;
  48. }
  49. static FILE *open_file(const char *name, const char *mode, const char (*searches)[PATH_MAX], int count) {
  50. int i;
  51. for (i = 0; i < count; i++) {
  52. char buffer[FILENAME_MAX + PATH_MAX];
  53. FILE *fp;
  54. #ifndef _MSC_VER
  55. snprintf(buffer, sizeof(buffer), "%s/%s", searches[i], name);
  56. #else
  57. _snprintf(buffer, sizeof(buffer), "%s/%s", searches[i], name);
  58. #endif
  59. if ((fp = fopen(buffer, mode)))
  60. return fp;
  61. }
  62. return !count ? fopen(name, mode) : NULL;
  63. }
  64. static int strcicmp(const char *s1, const char *s2) {
  65. const unsigned char *us1 = (const unsigned char *)s1,
  66. *us2 = (const unsigned char *)s2;
  67. while (tolower(*us1) == tolower(*us2)) {
  68. if (*us1++ == '\0')
  69. return 0;
  70. us2++;
  71. }
  72. return tolower(*us1) - tolower(*us2);
  73. }
  74. /* styles */
  75. enum { kCamel, kSnake };
  76. /* identifiers */
  77. enum { kData, kEnd, kSize };
  78. static const char *styled(int style, int ident) {
  79. switch (style) {
  80. case kCamel:
  81. switch (ident) {
  82. case kData: return "Data";
  83. case kEnd: return "End";
  84. case kSize: return "Size";
  85. }
  86. break;
  87. case kSnake:
  88. switch (ident) {
  89. case kData: return "_data";
  90. case kEnd: return "_end";
  91. case kSize: return "_size";
  92. }
  93. break;
  94. }
  95. }
  96. int main(int argc, char **argv) {
  97. int ret, i, paths, files = 0, style = kCamel;
  98. char outfile[FILENAME_MAX] = "data.c";
  99. char search_paths[SEARCH_PATHS_MAX][PATH_MAX];
  100. char prefix[FILENAME_MAX] = "g";
  101. char file_paths[FILE_PATHS_MAX][PATH_MAX];
  102. FILE *out = NULL;
  103. argc--;
  104. argv++;
  105. #define s(IDENT) styled(style, IDENT)
  106. if (argc == 0) {
  107. usage:
  108. fprintf(stderr, "%s [-help] [-Ipath...] | <files> | [-o output] | [-p prefix]\n", argv[-1]);
  109. fprintf(stderr, " -o - output file [default is \"data.c\"]\n");
  110. fprintf(stderr, " -p - specify a prefix for symbol names (default is \"g\")\n");
  111. fprintf(stderr, " -S<style> - specify a style for symbol generation (default is \"camelcase\")\n");
  112. fprintf(stderr, " -I<path> - specify an include path for the tool to use\n");
  113. fprintf(stderr, " -help - this\n");
  114. fprintf(stderr, "example:\n");
  115. fprintf(stderr, " %s icon.png music.mp3 -o file.c\n", argv[-1]);
  116. fprintf(stderr, "styles (for -S):\n");
  117. fprintf(stderr, " camelcase\n");
  118. fprintf(stderr, " snakecase\n");
  119. return 1;
  120. }
  121. for (i = 0, paths = 0; i < argc; i++) {
  122. if (!strcmp(argv[i], "-o")) {
  123. if (i + 1 < argc) {
  124. strcpy(outfile, argv[i + 1]);
  125. memmove(argv+i+1, argv+i+2, (argc-i-2) * sizeof *argv);
  126. argc--;
  127. continue;
  128. }
  129. } else if (!strcmp(argv[i], "-p")) {
  130. /* supports "-p" with no prefix as well as
  131. * "-p -" which is another way of saying "no prefix"
  132. * and "-p <prefix>" for an actual prefix.
  133. */
  134. if (argv[i+1][0] == '-') {
  135. prefix[0] = '\0';
  136. /* is it just a -? */
  137. if (i + 1 < argc && !strcmp(argv[i+1], "-")) {
  138. memmove(argv+i+1, argv+i+2, (argc-i-2) * sizeof *argv);
  139. argc--;
  140. }
  141. continue;
  142. }
  143. strcpy(prefix, argv[i + 1]);
  144. memmove(argv+i+1, argv+i+2, (argc-i-2) * sizeof *argv);
  145. argc--;
  146. continue;
  147. } else if (!strncmp(argv[i], "-I", 2)) {
  148. char *name = argv[i] + 2; /* skip "-I"; */
  149. if (paths >= SEARCH_PATHS_MAX) {
  150. fprintf(stderr, "maximum search paths exceeded\n");
  151. return 1;
  152. }
  153. strcpy(search_paths[paths++], name);
  154. continue;
  155. } else if (!strncmp(argv[i], "-S", 2)) {
  156. char *name = argv[i] + 2; /* skip "-S"; */
  157. if (!strcicmp(name, "camel") || !strcicmp(name, "camelcase"))
  158. style = kCamel;
  159. else if (!strcicmp(name, "snake") || !strcicmp(name, "snakecase"))
  160. style = kSnake;
  161. else
  162. goto usage;
  163. continue;
  164. } else if (!strcmp(argv[i], "-help")) {
  165. goto usage;
  166. } else {
  167. if (files >= sizeof file_paths / sizeof *file_paths) {
  168. fprintf(stderr, "maximum file paths exceeded\n");
  169. return 1;
  170. }
  171. strcpy(file_paths[files++], argv[i]);
  172. }
  173. }
  174. if (!(out = fopen(outfile, "w"))) {
  175. fprintf(stderr, "failed to open `%s' for output\n", outfile);
  176. return 1;
  177. }
  178. fprintf(out, "/* File automatically generated by incbin */\n");
  179. /* Be sure to define the prefix if we're not using the default */
  180. if (strcmp(prefix, "g"))
  181. fprintf(out, "#define INCBIN_PREFIX %s\n", prefix);
  182. if (style != 0)
  183. fprintf(out, "#define INCBIN_STYLE INCBIN_STYLE_SNAKE\n");
  184. fprintf(out, "#include \"incbin.h\"\n\n");
  185. fprintf(out, "#ifdef __cplusplus\n");
  186. fprintf(out, "extern \"C\" {\n");
  187. fprintf(out, "#endif\n\n");
  188. for (i = 0; i < files; i++) {
  189. FILE *fp = open_file(file_paths[i], "r", search_paths, paths);
  190. char *line = NULL;
  191. size_t size = 0;
  192. if (!fp) {
  193. fprintf(stderr, "failed to open `%s' for reading\n", file_paths[i]);
  194. fclose(out);
  195. return 1;
  196. }
  197. while (fline(&line, &size, fp) != -1) {
  198. char *inc, *beg, *sep, *end, *name, *file;
  199. FILE *f;
  200. if (!(inc = strstr(line, "INCBIN"))) continue;
  201. if (!(beg = strchr(inc, '('))) continue;
  202. if (!(sep = strchr(beg, ','))) continue;
  203. if (!(end = strchr(sep, ')'))) continue;
  204. name = beg + 1;
  205. file = sep + 1;
  206. while (isspace(*name)) name++;
  207. while (isspace(*file)) file++;
  208. sep--;
  209. while (isspace(*sep)) sep--;
  210. *++sep = '\0';
  211. end--;
  212. while (isspace(*end)) end--;
  213. *++end = '\0';
  214. fprintf(out, "/* INCBIN(%s, %s); */\n", name, file);
  215. fprintf(out, "INCBIN_CONST INCBIN_ALIGN unsigned char %s%s%s[] = {\n ", prefix, name, s(kData));
  216. *--end = '\0';
  217. file++;
  218. if (!(f = open_file(file, "rb", search_paths, paths))) {
  219. fprintf(stderr, "failed to include data `%s'\n", file);
  220. goto end;
  221. } else {
  222. long size, i;
  223. unsigned char *data, count;
  224. fseek(f, 0, SEEK_END);
  225. size = ftell(f);
  226. fseek(f, 0, SEEK_SET);
  227. if (!(data = (unsigned char *)malloc(size))) {
  228. fprintf(stderr, "out of memory\n");
  229. fclose(f);
  230. ret = 1;
  231. goto end;
  232. }
  233. if (fread(data, size, 1, f) != 1) {
  234. fprintf(stderr, "failed reading include data `%s'\n", file);
  235. free(data);
  236. fclose(f);
  237. ret = 1;
  238. goto end;
  239. }
  240. for (i = 0; i < size; i++) {
  241. if (count == 12) {
  242. fprintf(out, "\n ");
  243. count = 0;
  244. }
  245. fprintf(out, i != size - 1 ? "0x%02X, " : "0x%02X", data[i]);
  246. count++;
  247. }
  248. free(data);
  249. fclose(f);
  250. }
  251. fprintf(out, "\n};\n");
  252. fprintf(out, "INCBIN_CONST INCBIN_ALIGN unsigned char *const %s%s%s = g%s%s + sizeof(g%s%s);\n", prefix, name, s(kEnd), name, s(kData), name, s(kData));
  253. fprintf(out, "INCBIN_CONST unsigned int %s%s%s = sizeof(g%s%s);\n", prefix, name, s(kSize), name, s(kData));
  254. }
  255. end:
  256. free(line);
  257. fclose(fp);
  258. printf("included `%s'\n", file_paths[i]);
  259. }
  260. if (ret == 0) {
  261. fprintf(out, "\n#ifdef __cplusplus\n");
  262. fprintf(out, "}\n");
  263. fprintf(out, "#endif\n");
  264. fclose(out);
  265. printf("generated `%s'\n", outfile);
  266. return 0;
  267. }
  268. fclose(out);
  269. remove(outfile);
  270. return 1;
  271. }