daily pastebin goal
35%
SHARE
TWEET

bin2h v0.2

8bitbubsy Oct 18th, 2018 (edited) 98 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. #ifdef _WIN32
  2. #define WIN32_LEAN_AND_MEAN
  3. #include <windows.h>
  4. #include <shlwapi.h>
  5. #endif
  6. #include <stdio.h>
  7. #include <string.h> // stricmp()
  8. #include <stdlib.h> // atoi()
  9. #include <ctype.h>  // toupper()
  10. #include <stdint.h>
  11. #include <stdbool.h>
  12.  
  13. // if compiling for Windows, you need to link shlwapi.lib (for PathRemoveFileSpecW())
  14.  
  15. #define CLAMP(x, low, high) (((x) > (high)) ? (high) : (((x) < (low)) ? (low) : (x)))
  16.  
  17. #define IO_BUF_SIZE        4096
  18. #define MAX_NAME_LEN       64
  19. #define DATA_NAME          "hdata" // this has to be a legal C variable name
  20. #define BYTES_PER_LINE     24
  21. #define MAX_MEGABYTES_IN   4
  22. #define MIN_BYTES_PER_LINE 1
  23. #define MAX_BYTES_PER_LINE 64
  24.  
  25. static const char hex2ch[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
  26. static char fileNameOut[MAX_NAME_LEN + 8], dataType[32];
  27. static char dataName[MAX_NAME_LEN + 1], dataNameUpper[MAX_NAME_LEN + 1];
  28. static bool useConstFlag = true, addZeroFlag = false;
  29. static size_t fileSize, bytesPerLine = BYTES_PER_LINE, dataNameLen;
  30.  
  31. #ifdef _WIN32
  32. static void setDirToExecutablePath(void);
  33. #endif
  34.  
  35. static void setNewDataName(const char *name);
  36. static bool handleArguments(int argc, char *argv[]);
  37. static bool compareFileNames(const char *path1, const char *path2);
  38. static bool setAndTestFileSize(FILE *f);
  39. static bool writeHeader(FILE *f);
  40.  
  41. int main(int argc, char *argv[])
  42. {
  43.     uint8_t byte, readBuffer[IO_BUF_SIZE], writeBuffer[IO_BUF_SIZE * 6]; // don't mess with the sizes here
  44.     size_t i, lineEntry, readLength, writeLength, bytesWritten;
  45.     FILE *fIn, *fOut;
  46.  
  47. #ifdef _WIN32 // path is not set to cwd in XP (with VS2017 runtime) for some reason
  48.     setDirToExecutablePath();
  49. #endif
  50.  
  51.     strcpy(dataType, "uint8_t");
  52.     setNewDataName(DATA_NAME);
  53.  
  54.     printf("bin2h v0.2 - by 8bitbubsy 2018-2019 - Converts a binary to a C include file\n");
  55.     printf("===========================================================================\n");
  56.  
  57.     // handle input arguments
  58.     if (!handleArguments(argc, argv))
  59.         return (-1);
  60.  
  61.     // test if the output file is the same as the input file (illegal)
  62.     if (compareFileNames(argv[1], fileNameOut))
  63.     {
  64.         printf("Error: Output file can't be the same as input file!\n");
  65.         return (1);
  66.     }
  67.  
  68.     // open input file
  69.     fIn = fopen(argv[1], "rb");
  70.     if (fIn == NULL)
  71.     {
  72.         printf("Error: Could not open input file for reading!\n");
  73.         return (1);
  74.     }
  75.  
  76.     // get filesize and test if it's 0 or too high
  77.     if (!setAndTestFileSize(fIn))
  78.     {
  79.         fclose(fIn);
  80.         return (1);
  81.     }
  82.  
  83.     // open output file
  84.     fOut = fopen(fileNameOut, "w");
  85.     if (fOut == NULL)
  86.     {
  87.         fclose(fIn);
  88.  
  89.         printf("Error: Could not open data.h for writing!\n");
  90.         return (1);
  91.     }
  92.  
  93.     // write .h header
  94.     if (!writeHeader(fOut))
  95.         goto IOError;
  96.  
  97.     // write main data
  98.  
  99.     printf("Reading/writing from/to files...\n");
  100.  
  101.     bytesWritten = 0;
  102.     while (!feof(fIn))
  103.     {
  104.         readLength = fread(readBuffer, 1, IO_BUF_SIZE, fIn);
  105.  
  106.         writeLength = 0;
  107.         for (i = 0; i < readLength; ++i)
  108.         {
  109.             lineEntry = bytesWritten % bytesPerLine;
  110.  
  111.             // put tab if we're at the start of a line
  112.             if (lineEntry == 0)
  113.                 writeBuffer[writeLength++] = '\t';
  114.  
  115.             // write table entry
  116.  
  117.             byte = readBuffer[i];
  118.             if (bytesWritten == (fileSize - 1))
  119.             {
  120.                 // last byte in table
  121.  
  122.                 if (addZeroFlag) // fileSize is increased by one if addZeroFlag = true
  123.                 {
  124.                     writeBuffer[writeLength++] = '\0';
  125.                 }
  126.                 else
  127.                 {
  128.                     // "0xXX"
  129.                     writeBuffer[writeLength++] = '0';
  130.                     writeBuffer[writeLength++] = 'x';
  131.                     writeBuffer[writeLength++] = hex2ch[byte >> 4];
  132.                     writeBuffer[writeLength++] = hex2ch[byte & 15];
  133.                 }
  134.             }
  135.             else
  136.             {
  137.                 // "0xXX,"
  138.                 writeBuffer[writeLength++] = '0';
  139.                 writeBuffer[writeLength++] = 'x';
  140.                 writeBuffer[writeLength++] = hex2ch[byte >> 4];
  141.                 writeBuffer[writeLength++] = hex2ch[byte & 15];
  142.                 writeBuffer[writeLength++] = ',';
  143.             }
  144.  
  145.             // put linefeed if we're at the end of a line (or at the last byte entry)
  146.             if ((lineEntry == (bytesPerLine - 1)) || (bytesWritten == (fileSize - 1)))
  147.                 writeBuffer[writeLength++] = '\n';
  148.  
  149.             bytesWritten++;
  150.         }
  151.  
  152.         if (fwrite(writeBuffer, 1, writeLength, fOut) != writeLength)
  153.             goto IOError;
  154.     }
  155.  
  156.     if (bytesWritten != fileSize)
  157.         goto IOError;
  158.  
  159.     // write .h footer
  160.     if (fprintf(fOut, "};\n") < 0) goto IOError;
  161.     if (fprintf(fOut, "\n") < 0) goto IOError;
  162.     if (fprintf(fOut, "#endif\n") < 0) goto IOError;
  163.  
  164.     fclose(fOut);
  165.     fclose(fIn);
  166.  
  167.     printf("%d bytes sucessfully written to \"%s\".\n", fileSize, fileNameOut);
  168.     return (0);
  169.  
  170. IOError:
  171.     fclose(fOut);
  172.     fclose(fIn);
  173.  
  174.     printf("Error: General I/O fault during reading/writing!\n");
  175.     return (1);
  176. }
  177.  
  178. #ifdef _WIN32
  179. static void setDirToExecutablePath(void)
  180. {
  181.     WCHAR path[MAX_PATH];
  182.  
  183.     GetModuleFileNameW(GetModuleHandleW(NULL), path, MAX_PATH);
  184.     PathRemoveFileSpecW(path);
  185.     SetCurrentDirectoryW(path);
  186.  
  187.     // we don't care if this fails or not, so no error checking for now
  188. }
  189. #endif
  190.  
  191. static bool dataNameIsValid(const char *s, size_t len)
  192. {
  193.     bool charIsValid;
  194.     size_t i;
  195.  
  196.     for (i = 0; i < len; ++i)
  197.     {
  198.         if ((i == 0) && ((s[i] >= '0') && (s[i] <= '9')))
  199.             return (false); // a C variable can't start with a digit
  200.  
  201.         charIsValid = ((s[i] >= '0') && (s[i] <= '9')) ||
  202.             ((s[i] >= 'a') && (s[i] <= 'z')) ||
  203.             ((s[i] >= 'A') && (s[i] <= 'Z'));
  204.  
  205.         if (!charIsValid)
  206.             return (false);
  207.     }
  208.  
  209.     return (true);
  210. }
  211.  
  212. static void setNewDataName(const char *name)
  213. {
  214.     size_t i;
  215.  
  216.     strncpy(dataName, name, sizeof(dataName) - 1);
  217.     dataNameLen = strlen(dataName);
  218.     sprintf(fileNameOut, "%s.h", dataName);
  219.  
  220.     // maker upper case version of dataName
  221.     for (i = 0; i < dataNameLen; ++i)
  222.         dataNameUpper[i] = (char)(toupper(dataName[i]));
  223.     dataNameUpper[i] = '\0';
  224.  
  225.     // test if dataName is valid for use in a C header
  226.     if (!dataNameIsValid(dataName, dataNameLen))
  227.     {
  228.         strcpy(dataName, DATA_NAME);
  229.         printf("Warning: Data name was illegal and was set to default (%s).\n", DATA_NAME);
  230.     }
  231. }
  232.  
  233. static bool handleArguments(int argc, char *argv[])
  234. {
  235.     int32_t i;
  236.  
  237.     if (argc < 2)
  238.     {
  239.         printf("Usage: bin2h <binary> [options]\n");
  240.         printf("\n");
  241.         printf("Options:\n");
  242.         printf(" --no-const   Don't declare data as const\n");
  243.         printf(" --signed     Declare data as signed instead of unsigned\n");
  244.         printf(" --terminate  Insert a zero after the data (also increases length constant by 1)\n");
  245.         printf(" -n <name>    Set data name (max %d chars, a-zA-Z0-9_, default = %s)\n", MAX_NAME_LEN, DATA_NAME);
  246.         printf(" -b <num>     Set amount of bytes per line in data table (%d..%d, default = %d)\n",
  247.             MIN_BYTES_PER_LINE, MAX_BYTES_PER_LINE, BYTES_PER_LINE);
  248.  
  249.         return (false);
  250.     }
  251.     else
  252.     {
  253.         for (i = 0; i < argc; ++i)
  254.         {
  255.             if (_stricmp(argv[i], "--no-const") == 0)
  256.             {
  257.                 useConstFlag = false;
  258.             }
  259.             if (_stricmp(argv[i], "--terminate") == 0)
  260.             {
  261.                 addZeroFlag = true;
  262.             }
  263.             if (_stricmp(argv[i], "--signed") == 0)
  264.             {
  265.                 strcpy(dataType, "int8_t");
  266.             }
  267.             else if (_stricmp(argv[i], "-n") == 0)
  268.             {
  269.                 if (i < (argc - 1))
  270.                     setNewDataName(argv[i + 1]);
  271.             }
  272.             else if (_stricmp(argv[i], "-b") == 0)
  273.             {
  274.                 if (i < (argc - 1))
  275.                     bytesPerLine = CLAMP(atoi(argv[i + 1]), MIN_BYTES_PER_LINE, MAX_BYTES_PER_LINE);
  276.             }
  277.         }
  278.     }
  279.  
  280.     return (true);
  281. }
  282.  
  283. // compares two filenames (mixed full path or not, case insensitive)
  284. static bool compareFileNames(const char *path1, const char *path2)
  285. {
  286.     char sep;
  287.     const char *p1, *p2;
  288.     size_t i, l1, l2;
  289.  
  290.     if ((path1 == NULL) || (path2 == NULL))
  291.         return (false); // error
  292.  
  293. #ifdef _WIN32
  294.     sep = '\\';
  295. #else
  296.     sep = '/';
  297. #endif
  298.  
  299.     // set pointers to first occurrences of separator in paths
  300.     p1 = strrchr(path1, sep);
  301.     p2 = strrchr(path2, sep);
  302.  
  303.     if (p1 == NULL)
  304.     {
  305.         // separator not found, point to start of path
  306.         p1 = path1;
  307.         l1 = strlen(p1);
  308.     }
  309.     else
  310.     {
  311.         // separator found, increase pointer by 1 if we have room
  312.         l1 = strlen(p1);
  313.         if (l1 > 0)
  314.         {
  315.             p1++;
  316.             l1--;
  317.         }
  318.     }
  319.  
  320.     if (p2 == NULL)
  321.     {
  322.         // separator not found, point to start of path
  323.         p2 = path2;
  324.         l2 = strlen(p2);
  325.     }
  326.     else
  327.     {
  328.         // separator found, increase pointer by 1 if we have room
  329.         l2 = strlen(p2);
  330.         if (l2 > 0)
  331.         {
  332.             p2++;
  333.             l2--;
  334.         }
  335.     }
  336.  
  337.     if (l1 != l2)
  338.         return (false); // definitely not the same
  339.  
  340.     // compare strings
  341.     for (i = 0; i < l1; ++i)
  342.     {
  343.         if (tolower(p1[i]) != tolower(p2[i]))
  344.             return (false); // not the same
  345.     }
  346.  
  347.     return (true); // both filenames are the same
  348. }
  349.  
  350. static bool setAndTestFileSize(FILE *f)
  351. {
  352.     fseek(f, 0, SEEK_END);
  353.     fileSize = ftell(f);
  354.     rewind(f);
  355.  
  356.     if (fileSize == 0)
  357.     {
  358.         printf("Error: Input file is empty!\n");
  359.         return (false);
  360.     }
  361.  
  362.     if (fileSize > (MAX_MEGABYTES_IN * (1024UL * 1024UL)))
  363.     {
  364.         printf("Error: The input filesize is over %dMB. This program is meant for small files!\n", MAX_MEGABYTES_IN);
  365.         return (false);
  366.     }
  367.  
  368.     if (addZeroFlag)
  369.         fileSize++; // make room for zero
  370.  
  371.     return (true);
  372. }
  373.  
  374. static bool writeHeader(FILE *f)
  375. {
  376.     if (fprintf(f, "#ifndef __%s_H\n", dataNameUpper) < 0) return (false);
  377.     if (fprintf(f, "#define __%s_H\n", dataNameUpper) < 0) return (false);
  378.     if (fprintf(f, "\n") < 0) return (false);
  379.     if (fprintf(f, "#include <stdint.h>\n") < 0) return (false);
  380.     if (fprintf(f, "\n") < 0) return (false);
  381.     if (fprintf(f, "#define %s_LENGTH %d\n", dataNameUpper, fileSize) < 0) return (false);
  382.     if (fprintf(f, "\n") < 0) return (false);
  383.  
  384.     if (useConstFlag)
  385.     {
  386.         if (fprintf(f, "const %s %s[%s_LENGTH] =\n", dataType, dataName, dataNameUpper) < 0)
  387.             return (false);
  388.     }
  389.     else
  390.     {
  391.         if (fprintf(f, "%s %s[%s_LENGTH] =\n", dataType, dataName, dataNameUpper) < 0)
  392.             return (false);
  393.     }
  394.  
  395.     if (fprintf(f, "{\n") < 0)
  396.         return (false);
  397.  
  398.     return (true);
  399. }
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top