Advertisement
8bitbubsy

bin2h v0.2

Oct 18th, 2018
765
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 9.46 KB | None | 0 0
  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 8
  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;
  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 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 (size_t 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.  
  195.     for (size_t i = 0; i < len; i++)
  196.     {
  197.         if (i == 0 && (s[i] >= '0' && s[i] <= '9'))
  198.             return false; // a C variable can't start with a digit
  199.  
  200.         charIsValid = (s[i] >= '0' && s[i] <= '9') ||
  201.                       (s[i] >= 'a' && s[i] <= 'z') ||
  202.                       (s[i] >= 'A' && s[i] <= 'Z');
  203.  
  204.         if (!charIsValid)
  205.             return false;
  206.     }
  207.  
  208.     return true;
  209. }
  210.  
  211. static void setNewDataName(const char *name)
  212. {
  213.     size_t i;
  214.  
  215.     strncpy(dataName, name, sizeof (dataName)-1);
  216.     dataNameLen = strlen(dataName);
  217.     sprintf(fileNameOut, "%s.h", dataName);
  218.  
  219.     // maker upper case version of dataName
  220.     for (i = 0; i < dataNameLen; i++)
  221.         dataNameUpper[i] = (char)toupper(dataName[i]);
  222.     dataNameUpper[i] = '\0';
  223.  
  224.     // test if dataName is valid for use in a C header
  225.     if (!dataNameIsValid(dataName, dataNameLen))
  226.     {
  227.         strcpy(dataName, DATA_NAME);
  228.         printf("Warning: Data name was illegal and was set to default (%s).\n", DATA_NAME);
  229.     }
  230. }
  231.  
  232. static bool handleArguments(int argc, char *argv[])
  233. {
  234.     if (argc < 2)
  235.     {
  236.         printf("Usage: bin2h <binary> [options]\n");
  237.         printf("\n");
  238.         printf("Options:\n");
  239.         printf(" --no-const   Don't declare data as const\n");
  240.         printf(" --signed     Declare data as signed instead of unsigned\n");
  241.         printf(" --terminate  Insert a zero after the data (also increases length constant by 1)\n");
  242.         printf(" -n <name>    Set data name (max %d chars, a-zA-Z0-9_, default = %s)\n", MAX_NAME_LEN, DATA_NAME);
  243.         printf(" -b <num>     Set amount of bytes per line in data table (%d..%d, default = %d)\n",
  244.             MIN_BYTES_PER_LINE, MAX_BYTES_PER_LINE, BYTES_PER_LINE);
  245.  
  246.         return false;
  247.     }
  248.     else
  249.     {
  250.         for (int32_t i = 0; i < argc; i++)
  251.         {
  252.             if (!_stricmp(argv[i], "--no-const"))
  253.             {
  254.                 useConstFlag = false;
  255.             }
  256.             if (!_stricmp(argv[i], "--terminate"))
  257.             {
  258.                 addZeroFlag = true;
  259.             }
  260.             if (!_stricmp(argv[i], "--signed"))
  261.             {
  262.                 strcpy(dataType, "int8_t");
  263.             }
  264.             else if (!_stricmp(argv[i], "-n"))
  265.             {
  266.                 if (i < argc-1)
  267.                     setNewDataName(argv[i+1]);
  268.             }
  269.             else if (!_stricmp(argv[i], "-b"))
  270.             {
  271.                 if (i < argc-1)
  272.                     bytesPerLine = CLAMP(atoi(argv[i+1]), MIN_BYTES_PER_LINE, MAX_BYTES_PER_LINE);
  273.             }
  274.         }
  275.     }
  276.  
  277.     return true;
  278. }
  279.  
  280. // compares two filenames (mixed full path or not, case insensitive)
  281. static bool compareFileNames(const char *path1, const char *path2)
  282. {
  283.     char sep;
  284.     const char *p1, *p2;
  285.     size_t l1, l2;
  286.  
  287.     if (path1 == NULL || path2 == NULL)
  288.         return false; // error
  289.  
  290. #ifdef _WIN32
  291.     sep = '\\';
  292. #else
  293.     sep = '/';
  294. #endif
  295.  
  296.     // set pointers to first occurrences of separator in paths
  297.     p1 = strrchr(path1, sep);
  298.     p2 = strrchr(path2, sep);
  299.  
  300.     if (p1 == NULL)
  301.     {
  302.         // separator not found, point to start of path
  303.         p1 = path1;
  304.         l1 = strlen(p1);
  305.     }
  306.     else
  307.     {
  308.         // separator found, increase pointer by 1 if we have room
  309.         l1 = strlen(p1);
  310.         if (l1 > 0)
  311.         {
  312.             p1++;
  313.             l1--;
  314.         }
  315.     }
  316.  
  317.     if (p2 == NULL)
  318.     {
  319.         // separator not found, point to start of path
  320.         p2 = path2;
  321.         l2 = strlen(p2);
  322.     }
  323.     else
  324.     {
  325.         // separator found, increase pointer by 1 if we have room
  326.         l2 = strlen(p2);
  327.         if (l2 > 0)
  328.         {
  329.             p2++;
  330.             l2--;
  331.         }
  332.     }
  333.  
  334.     if (l1 != l2)
  335.         return false; // definitely not the same
  336.  
  337.     // compare strings
  338.     for (size_t i = 0; i < l1; i++)
  339.     {
  340.         if (tolower(p1[i]) != tolower(p2[i]))
  341.             return false; // not the same
  342.     }
  343.  
  344.     return true; // both filenames are the same
  345. }
  346.  
  347. static bool setAndTestFileSize(FILE *f)
  348. {
  349.     fseek(f, 0, SEEK_END);
  350.     fileSize = ftell(f);
  351.     rewind(f);
  352.  
  353.     if (fileSize == 0)
  354.     {
  355.         printf("Error: Input file is empty!\n");
  356.         return false;
  357.     }
  358.  
  359.     if (fileSize > MAX_MEGABYTES_IN*(1024UL*1024))
  360.     {
  361.         printf("Error: The input filesize is over %dMB. This program is meant for small files!\n", MAX_MEGABYTES_IN);
  362.         return false;
  363.     }
  364.  
  365.     if (addZeroFlag)
  366.         fileSize++; // make room for zero
  367.  
  368.     return true;
  369. }
  370.  
  371. static bool writeHeader(FILE *f)
  372. {
  373.     if (fprintf(f, "#ifndef __%s_H\n", dataNameUpper) < 0) return false;
  374.     if (fprintf(f, "#define __%s_H\n", dataNameUpper) < 0) return false;
  375.     if (fprintf(f, "\n") < 0) return false;
  376.     if (fprintf(f, "#include <stdint.h>\n") < 0) return false;
  377.     if (fprintf(f, "\n") < 0) return false;
  378.     if (fprintf(f, "#define %s_LENGTH %d\n", dataNameUpper, fileSize) < 0) return false;
  379.     if (fprintf(f, "\n") < 0) return false;
  380.  
  381.     if (useConstFlag)
  382.     {
  383.         if (fprintf(f, "const %s %s[%s_LENGTH] =\n", dataType, dataName, dataNameUpper) < 0)
  384.             return false;
  385.     }
  386.     else
  387.     {
  388.         if (fprintf(f, "%s %s[%s_LENGTH] =\n", dataType, dataName, dataNameUpper) < 0)
  389.             return false;
  390.     }
  391.  
  392.     if (fprintf(f, "{\n") < 0)
  393.         return false;
  394.  
  395.     return true;
  396. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement