bin2c.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /*
  2. * Copyright 2011-2020 Branimir Karadzic. All rights reserved.
  3. * License: https://github.com/bkaradzic/bx#license-bsd-2-clause
  4. */
  5. #include <bx/allocator.h>
  6. #include <bx/commandline.h>
  7. #include <bx/file.h>
  8. #include <bx/string.h>
  9. #include <bx/debug.h>
  10. class Bin2cWriter : public bx::WriterI
  11. {
  12. public:
  13. Bin2cWriter(bx::AllocatorI* _allocator, const bx::StringView& _name)
  14. : m_mb(_allocator)
  15. , m_mw(&m_mb)
  16. , m_name(_name)
  17. , m_outputAsCStr(false)
  18. {
  19. }
  20. virtual ~Bin2cWriter()
  21. {
  22. }
  23. virtual int32_t write(const void* _data, int32_t _size, bx::Error* _err) override
  24. {
  25. m_outputAsCStr = true;
  26. const char* data = (const char*)_data;
  27. for (int32_t ii = 0; ii < _size; ++ii)
  28. {
  29. char ch = data[ii];
  30. if (!bx::isPrint(ch)
  31. && !bx::isSpace(ch) )
  32. {
  33. m_outputAsCStr = false;
  34. break;
  35. }
  36. }
  37. return bx::write(&m_mw, _data, _size, _err);
  38. }
  39. void output(bx::WriterI* _writer)
  40. {
  41. if (m_outputAsCStr)
  42. {
  43. outputString(_writer);
  44. }
  45. else
  46. {
  47. outputHex(_writer);
  48. }
  49. }
  50. void outputString(bx::WriterI* _writer)
  51. {
  52. const char* data = (const char*)m_mb.more(0);
  53. uint32_t size = uint32_t(bx::seek(&m_mw) );
  54. bx::Error err;
  55. bx::write(
  56. _writer
  57. , &err
  58. , "static const char* %.*s = /* Generated with bin2c. */\n\t\""
  59. , m_name.getLength()
  60. , m_name.getPtr()
  61. );
  62. if (NULL != data)
  63. {
  64. bool escaped = false;
  65. for (uint32_t ii = 0; ii < size; ++ii)
  66. {
  67. char ch = data[ii];
  68. if (!escaped)
  69. {
  70. switch (ch)
  71. {
  72. case '\"': bx::write(_writer, "\\\"", &err); break;
  73. case '\n': bx::write(_writer, "\\n\"\n\t\"", &err); break;
  74. case '\r': bx::write(_writer, "\\r", &err); break;
  75. case '\\': escaped = true; BX_FALLTHROUGH;
  76. default: bx::write(_writer, ch, &err); break;
  77. }
  78. }
  79. else
  80. {
  81. switch (ch)
  82. {
  83. case '\n': bx::write(_writer, "\\\"\n\t\"", &err); break;
  84. case '\r': BX_FALLTHROUGH;
  85. case '\t': bx::write(_writer, "\\", &err); BX_FALLTHROUGH;
  86. default : bx::write(_writer, ch, &err); break;
  87. }
  88. escaped = false;
  89. }
  90. }
  91. }
  92. bx::write(_writer, &err, "\"\n\t;\n");
  93. }
  94. void outputHex(bx::WriterI* _writer)
  95. {
  96. #define HEX_DUMP_WIDTH 16
  97. #define HEX_DUMP_SPACE_WIDTH 96
  98. #define HEX_DUMP_FORMAT "%-" BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "." BX_STRINGIZE(HEX_DUMP_SPACE_WIDTH) "s"
  99. const char* data = (const char*)m_mb.more(0);
  100. uint32_t size = uint32_t(bx::seek(&m_mw) );
  101. bx::Error err;
  102. bx::write(
  103. _writer
  104. , &err
  105. , "static const uint8_t %.*s[%d] = /* Generated with bin2c. */\n{\n"
  106. , m_name.getLength()
  107. , m_name.getPtr()
  108. , size
  109. );
  110. if (NULL != data)
  111. {
  112. char hex[HEX_DUMP_SPACE_WIDTH+1];
  113. char ascii[HEX_DUMP_WIDTH+1];
  114. uint32_t hexPos = 0;
  115. uint32_t asciiPos = 0;
  116. for (uint32_t ii = 0; ii < size; ++ii)
  117. {
  118. bx::snprintf(&hex[hexPos], sizeof(hex)-hexPos, "0x%02x, ", data[asciiPos]);
  119. hexPos += 6;
  120. ascii[asciiPos] = bx::isPrint(data[asciiPos]) && data[asciiPos] != '\\' ? data[asciiPos] : '.';
  121. asciiPos++;
  122. if (HEX_DUMP_WIDTH == asciiPos)
  123. {
  124. ascii[asciiPos] = '\0';
  125. bx::write(_writer, &err, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
  126. data += asciiPos;
  127. hexPos = 0;
  128. asciiPos = 0;
  129. }
  130. }
  131. if (0 != asciiPos)
  132. {
  133. ascii[asciiPos] = '\0';
  134. bx::write(_writer, &err, "\t" HEX_DUMP_FORMAT "// %s\n", hex, ascii);
  135. }
  136. }
  137. bx::write(_writer, &err, "};\n");
  138. #undef HEX_DUMP_WIDTH
  139. #undef HEX_DUMP_SPACE_WIDTH
  140. #undef HEX_DUMP_FORMAT
  141. }
  142. bx::MemoryBlock m_mb;
  143. bx::MemoryWriter m_mw;
  144. bx::StringView m_name;
  145. bool m_outputAsCStr;
  146. };
  147. void help(const char* _error = NULL)
  148. {
  149. bx::WriterI* stdOut = bx::getStdOut();
  150. bx::Error err;
  151. if (NULL != _error)
  152. {
  153. bx::write(stdOut, &err, "Error:\n%s\n\n", _error);
  154. }
  155. bx::write(stdOut, &err
  156. , "bin2c, binary to C\n"
  157. "Copyright 2011-2020 Branimir Karadzic. All rights reserved.\n"
  158. "License: https://github.com/bkaradzic/bx#license-bsd-2-clause\n\n"
  159. );
  160. bx::write(stdOut, &err
  161. , "Usage: bin2c -f <in> -o <out> -n <name>\n"
  162. "\n"
  163. "Options:\n"
  164. " -f <file path> Input file path.\n"
  165. " -o <file path> Output file path.\n"
  166. " -n <name> Array name.\n"
  167. "\n"
  168. "For additional information, see https://github.com/bkaradzic/bx\n"
  169. );
  170. }
  171. int main(int _argc, const char* _argv[])
  172. {
  173. bx::CommandLine cmdLine(_argc, _argv);
  174. if (cmdLine.hasArg('h', "help") )
  175. {
  176. help();
  177. return bx::kExitFailure;
  178. }
  179. bx::FilePath filePath = cmdLine.findOption('f');
  180. if (filePath.isEmpty() )
  181. {
  182. help("Input file name must be specified.");
  183. return bx::kExitFailure;
  184. }
  185. bx::FilePath outFilePath = cmdLine.findOption('o');
  186. if (outFilePath.isEmpty() )
  187. {
  188. help("Output file name must be specified.");
  189. return bx::kExitFailure;
  190. }
  191. bx::StringView name = cmdLine.findOption('n');
  192. if (name.isEmpty() )
  193. {
  194. name.set("data");
  195. }
  196. void* data = NULL;
  197. uint32_t size = 0;
  198. bx::FileReader fr;
  199. if (bx::open(&fr, filePath) )
  200. {
  201. size = uint32_t(bx::getSize(&fr) );
  202. bx::DefaultAllocator allocator;
  203. data = BX_ALLOC(&allocator, size);
  204. bx::read(&fr, data, size);
  205. bx::close(&fr);
  206. bx::FileWriter fw;
  207. if (bx::open(&fw, outFilePath) )
  208. {
  209. Bin2cWriter writer(&allocator, name);
  210. bx::write(&writer, data, size);
  211. writer.output(&fw);
  212. bx::close(&fw);
  213. }
  214. BX_FREE(&allocator, data);
  215. }
  216. return 0;
  217. }