8bitbubsy

bin2h v0.2

Oct 18th, 2018
261
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 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. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×