Advertisement
honey_the_codewitch

dumb

Jun 5th, 2025
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. import React, { useState, useRef } from 'react';
  2.  
  3. const toHex = (code) => {
  4.     let result = code.toString(16);
  5.     if (result.length == 1) {
  6.         return "0" + result;
  7.     }
  8.     return result;
  9. }
  10. const generateText = (data, startSpacing = 0) => {
  11.     let result = "\"";
  12.     const view = new DataView(data);
  13.     let j = startSpacing;
  14.     for (var i = 0; i < view.byteLength; i++) {
  15.         if (i > 0 && 0 == (j % 80) && i < i < view.byteLength - 1) {
  16.             result += "\"\r\n    \"";
  17.         }
  18.         var charcode = view.getUint8(i);
  19.         if (charcode < 0x80) {
  20.             const ch = String.fromCharCode(charcode);
  21.             switch (ch) {
  22.                 case '\r':
  23.                     result += "\\r";
  24.                     break;
  25.                 case '\n':
  26.                     result += "\\n";
  27.                     if (i < view.byteLength - 1) {
  28.                         result += "\"\r\n    \"";
  29.                     }
  30.                     j = 0;
  31.                     break;
  32.                 case '\t':
  33.                     result += "\\t";
  34.                     break;
  35.                 case '"':
  36.                     result += "\\\"";
  37.                     break;
  38.                 case '\\':
  39.                     result += "\\\\";
  40.                     break;
  41.                 default:
  42.                     result += ch;
  43.                     break;
  44.             }
  45.         }
  46.         else {
  47.             result += `\\x${toHex(charcode)}`;
  48.         }
  49.         ++j;
  50.     }
  51.     return result + "\"";
  52. }
  53. const generateBinary = (data) => {
  54.     let result = "";
  55.     const view = new DataView(data);
  56.     for (let i = 0; i < view.byteLength; ++i) {
  57.         if (0 == (i % (30))) {
  58.             if (i < view.byteLength - 1) {
  59.                 result += "\r\n    ";
  60.             } else {
  61.                 result += "\r\n";
  62.             }
  63.         }
  64.         let append = ("0x" + toHex(view.getUint8(i)));
  65.         if (i < view.byteLength - 1) {
  66.             append += ", ";
  67.         }
  68.         result += append;
  69.  
  70.     }
  71.     return result;
  72. }
  73.  
  74. const generateStringLiteral = (name, data, isStatic) => {
  75.     if (isStatic) {
  76.         return `static const char* ${name} = ${generateText(data, 18 + name.length)};`;
  77.     }
  78.     return `const char* ${name} = ${generateText(data, 18 + name.length)};`;
  79.  
  80. }
  81.  
  82. const generateByteArrayLiteral = (name, data, isStatic) => {
  83.     if (isStatic) {
  84.         return `static const uint8_t ${name}[] = {${generateBinary(data)}};`;
  85.     }
  86.     return `const uint8_t ${name}[] = {${generateBinary(data)}};`;
  87.  
  88. }
  89. const toIdentifier = (name) => {
  90.     let result = "";
  91.     if (name.length == 0) {
  92.         return "_";
  93.     }
  94.     if (name[0] >= '0' && name[0] <= '9') {
  95.         result = "_";
  96.     }
  97.     for (let i = 0; i < name.length; ++i) {
  98.         if ((name[i] >= '0' && name[i] <= '9') || (name[i] >= 'A' && name[i] <= 'Z') || (name[i] >= 'a' && name[i] <= 'z')) {
  99.             result += name[i];
  100.         } else {
  101.             result += "_";
  102.         }
  103.     }
  104.     return result;
  105. }
  106. const checkWinFontMagic = (data) => {
  107.     const view = new DataView(data);
  108.     return view.byteLength > 2 && view.getUint8(0) == 77 && view.getUint8(1) == 90;
  109. }
  110. const isTrueType = (name) => {
  111.     const n = name.toLowerCase();
  112.     return n.endsWith(".ttf") || n.endsWith(".otf");
  113. }
  114. const generateHeader = (identifier, fileName, isText, fileType, size, units, outputType, data) => {
  115.     let result = "";
  116.     const isGfx = (outputType != undefined && outputType.length > 0 && outputType != "C");
  117.     const guard = identifier.toUpperCase() + ((isGfx) ? "_HPP" : "_H");
  118.     const impl = identifier.toUpperCase() + "_IMPLEMENTATION";
  119.     result += "// Automatically generated by https://honeythecodewitch.com/gfx/header\r\n";
  120.     result += `// #define ${impl} in exactly one translation unit (.c/.cpp file) before including this header\r\n`
  121.     result += `#ifndef ${guard}\r\n`;
  122.     result += `#define ${guard}\r\n`;
  123.     if (!isText) {
  124.         result += "#include <stdint.h>\r\n";
  125.     }
  126.     let isSpecialized = false;
  127.     let isFon = false;
  128.     let isTtf = false;
  129.     let isVlw = false;
  130.     let isJpg = false;
  131.     let isPng = false;
  132.     if (isGfx) {
  133.         if (fileType == undefined || fileType == "" && fileName.toLowerCase().endsWith(".fon")) {
  134.             isFon = checkWinFontMagic(data);
  135.             isSpecialized = isFon;
  136.         } else if (fileType == "image/jpeg") {
  137.             isJpg = true;
  138.             isSpecialized = true;
  139.         } else if (fileType == "image/png") {
  140.             isPng = true;
  141.             isSpecialized = true;
  142.         } else if (fileName.toLowerCase().endsWith(".vlw")) {
  143.             isVlw = true;
  144.             isSpecialized = true;
  145.         } else if (isTrueType(fileName) && size && !isNaN(size) && size != 0 && units) {
  146.             isTtf = true;
  147.             isSpecialized = true;
  148.         }
  149.         if (isFon) {
  150.             result += "#include \"gfx_win_font.hpp\"\r\n\r\n";
  151.             result += `extern gfx::win_font ${identifier};\r\n`
  152.         } else if (isVlw) {
  153.             result += "#include \"gfx_vlw_font.hpp\"\r\n\r\n";
  154.             result += `extern gfx::vlw_font ${identifier};\r\n`
  155.         } else if (isJpg) {
  156.             result += "#include \"gfx_jpg_image.hpp\"\r\n\r\n";
  157.             result += `extern gfx::jpg_image ${identifier};\r\n`
  158.         } else if (isPng) {
  159.             result += "#include \"gfx_png_image.hpp\"\r\n\r\n";
  160.             result += `extern gfx::png_image ${identifier};\r\n`
  161.         } else if (isTtf) {
  162.             result += "#include \"gfx_ttf_font.hpp\"\r\n\r\n";
  163.             result += `extern gfx::ttf_font ${identifier};\r\n`
  164.         } else {
  165.             result += "#include \"gfx_core.hpp\"\r\n\r\n";
  166.             result += `extern gfx::const_buffer_stream ${identifier};\r\n`;
  167.         }
  168.     } else {
  169.         if (isText) {
  170.             const view = new DataView(data);
  171.             result += `#define ${identifier.toUpperCase()}_LENGTH (${view.byteLength})\r\n`;
  172.             result += "#ifdef __cplusplus\r\nextern \"C\"\r\n#else\r\nextern\r\n#endif\r\n";
  173.             result += `const char* ${identifier};\r\n`;
  174.         } else {
  175.             result += `const uint8_t ${identifier}[];\r\n`;
  176.         }
  177.     }
  178.     result += `#endif // ${guard}\r\n\r\n`;
  179.     result += `#ifdef ${impl}\r\n`;
  180.     if (isGfx) {
  181.         if (isText) {
  182.             result += generateStringLiteral(identifier + "_data", data, true) + "\r\n\r\n";
  183.         } else {
  184.             result += generateByteArrayLiteral(identifier + "_data", data, true) + "\r\n\r\n";
  185.         }
  186.         if (isSpecialized) {
  187.             result += `static gfx::const_buffer_stream ${identifier}_stream(${identifier}_data,sizeof(${identifier}_data));\r\n`;
  188.         }
  189.         if (isFon) {
  190.             result += `gfx::win_font ${identifier}(${identifier}_stream);\r\n`;
  191.         } else if (isVlw) {
  192.             result += `gfx::vlw_font ${identifier}(${identifier}_stream);\r\n`;
  193.         } else if (isJpg) {
  194.             result += `gfx::jpg_image ${identifier}(${identifier}_stream);\r\n`;
  195.         } else if (isPng) {
  196.             result += `gfx::png_image ${identifier}(${identifier}_stream);\r\n`;
  197.         } else if (isTtf) {
  198.             result += `gfx::ttf_font ${identifier}(${identifier}_stream, ${size}, gfx::font_size_units::${units})\r\n`;
  199.         } else {
  200.             if (isText) {
  201.                 const view = new DataView(data);
  202.                 result += `gfx::const_buffer_stream ${identifier}((const uint8_t*)${identifier}_data,${view.byteLength});\r\n`;
  203.             } else {
  204.                 result += `gfx::const_buffer_stream ${identifier}(${identifier}_data,sizeof(${identifier}_data));\r\n`;
  205.             }
  206.         }
  207.     } else {
  208.         if (isText) {
  209.             result += generateStringLiteral(identifier, data, false) + "\r\n";
  210.         } else {
  211.             result += generateByteArrayLiteral(identifier, data, false) + "\r\n";
  212.         }
  213.     }
  214.     result += `#endif // ${impl}\r\n`;
  215.     return result;
  216. }
  217. const getDownloadName = (ident, genType) => {
  218.     if (genType == "C" || genType == undefined || genType == "") {
  219.         return `${ident}.h`;
  220.     }
  221.     return `${ident}.hpp`;
  222. }
  223. const HeaderGenerator = () => {
  224.     var gencache;
  225.     const [fileInfo, setFileInfo] = useState("");
  226.     const [ident, setIdent] = useState("");
  227.     const [fontSize, setFontSize] = useState("");
  228.     const [fontUnits, setFontUnits] = useState("");
  229.     const [genType, setGenType] = useState("");
  230.     const [downloadUrl, setDownloadUrl] = useState("");
  231.     const downloadLinkRef = useRef(null);
  232.     const isText = (type) => {
  233.         return (type.endsWith("/json") || type.endsWith("/xml") || type.endsWith("+xml") || type.startsWith("text/"));
  234.     }
  235.     const handleFileChange = (e) => {
  236.         setFileInfo({ file: e.target.files[0], type: e.target.files[0].type });
  237.         setIdent(toIdentifier(e.target.files[0].name));
  238.         gencache = undefined;
  239.     };
  240.     const handleIdentChange = (e) => {
  241.         if (ident != e.target.value) {
  242.             setIdent(e.target.value);
  243.             gencache = undefined;
  244.         }
  245.     }
  246.     const handleFontSizeValueChange = (e) => {
  247.         let n = Number.parseInt(e.target.value);
  248.         if (isNaN(n)) {
  249.             n = 0;
  250.         }
  251.         setFontSize(n);
  252.         gencache = undefined;
  253.     }
  254.     const handleFontSizeUnitChange = (e) => {
  255.         let u = e.target.value;
  256.         if (u != "pt" && u != "px") {
  257.             u = "pt";
  258.         }
  259.         setFontUnits(u);
  260.         gencache = undefined;
  261.     }
  262.     const handleTypeChange = (e) => {
  263.         if (genType != e.target.value) {
  264.             setGenType(e.target.value);
  265.             gencache = undefined;
  266.         }
  267.     }
  268.     const getCreatedTypeName = () => {
  269.         if (fileInfo) {
  270.             if(!genType || genType=="" || genType=="C") {
  271.                 if(isText(fileInfo.type)) {
  272.                     return "const char*";
  273.                 } else {
  274.                     return "const uint8_t[]";
  275.                 }
  276.             }
  277.             const fileType = fileInfo.type;
  278.             const fileName = fileInfo.file.name;
  279.             const size = fontSize;
  280.             const units = fontUnits;
  281.             if (fileType == undefined || fileType == "" && fileName.toLowerCase().endsWith(".fon")) {
  282.                 return "gfx::win_font";
  283.             } else if (fileType == "image/jpeg") {
  284.                 return "gfx::jpg_image";
  285.             } else if (fileType == "image/png") {
  286.                 return "gfx::png_image";
  287.             } else if (fileName.toLowerCase().endsWith(".vlw")) {
  288.                 return "gfx::vlw_font";
  289.             } else if (isTrueType(fileName) && size && !isNaN(size) && size != 0 && units) {
  290.                 return "gfx::ttf_font";
  291.             }
  292.  
  293.             return "gfx::const_buffer_stream";
  294.            
  295.         }
  296.         return undefined;
  297.     }
  298.  
  299.     const generateContentClip = () => {
  300.         if (!gencache && fileInfo.file) {
  301.             let reader = new FileReader();
  302.             reader.readAsArrayBuffer(fileInfo.file);
  303.             reader.onload = async function (evt) {
  304.                 console.log("generating content to clipboard");
  305.                 gencache = generateHeader(ident, fileInfo.file.name, isText(fileInfo.type), fileInfo.type, fontSize, fontUnits, genType, evt.target.result);
  306.                 await navigator.clipboard.writeText(gencache);
  307.             }
  308.         } else if (gencache) {
  309.             console.log("writing content to clipboard");
  310.             navigator.clipboard.writeText(gencache);
  311.         }
  312.     }
  313.     const setGeneratedFileUrl = () => {
  314.         const blb = new Blob([gencache], { type: "text/plain" });
  315.         if (downloadUrl != undefined && downloadUrl.length > 0) {
  316.             URL.revokeObjectURL(downloadUrl);
  317.         }
  318.         setDownloadUrl(URL.createObjectURL(blb));
  319.         downloadLinkRef?.current.click();
  320.     }
  321.     const generateContentFile = () => {
  322.         if (!gencache && fileInfo.file) {
  323.             let reader = new FileReader();
  324.             reader.readAsArrayBuffer(fileInfo.file);
  325.             reader.onload = function (evt) {
  326.                 console.log("generating content to file");
  327.                 gencache = generateHeader(ident, fileInfo.file.name, isText(fileInfo.type), fileInfo.type, fontSize, fontUnits, genType, evt.target.result);
  328.                 setGeneratedFileUrl();
  329.             }
  330.         } else if (gencache) {
  331.             console.log("writing content to file");
  332.             setGeneratedFileUrl();
  333.         }
  334.     }
  335.     const onDropFiles = (e) => {
  336.         e.preventDefault();
  337.         const inputFile = document.getElementById("file");
  338.         inputFile.files = e.dataTransfer.files;
  339.         setFileInfo({ file: e.dataTransfer.files[0], type: e.dataTransfer.files[0].type });
  340.         setIdent(toIdentifier(e.dataTransfer.files[0].name));
  341.         gencache = undefined;
  342.     }
  343.     return (
  344.         <div id="drop-target" onDrop={onDropFiles} className={"border-drag"} onDragOver={(event) => event.preventDefault()}>
  345.             <p>Select or drag a file here</p>
  346.             <div className="input-group">
  347.                 <table border="0">
  348.                     <tbody>
  349.                         <tr>
  350.                             <td colSpan={2}><input id="file" type="file" onChange={handleFileChange} /></td>
  351.                         </tr>
  352.                         <tr>
  353.                             <td><label>Type</label></td>
  354.                             <td>
  355.                                 <select id="type" value={genType} onChange={handleTypeChange}>
  356.                                     <option value="C">Raw C/++</option>
  357.                                     <option value="GFX2">GFX 2.x</option>
  358.                                 </select>
  359.                             </td>
  360.                         </tr>
  361.                         <tr>
  362.                             <td><label>Identifier: </label></td><td><input type="text" id="identifier" value={ident} onChange={handleIdentChange} /></td>
  363.                         </tr>
  364.                         {fileInfo && isTrueType(fileInfo.file.name) && genType.startsWith("G") && (
  365.                             <tr>
  366.                                 <td><label>Size: </label></td><td><input type="text" defaultValue={fontSize} onChange={handleFontSizeValueChange} /><select onChange={handleFontSizeUnitChange} defaultValue={fontUnits}><option value="pt">pt</option><option value="px">px</option></select></td>
  367.                             </tr>
  368.                         )}
  369.                     </tbody>
  370.                 </table>
  371.             </div>
  372.             {fileInfo && (
  373.                 <section>
  374.                     File details:
  375.                     <ul>
  376.                         <li>Name: {fileInfo.file.name}</li>
  377.                         {fileInfo.file.type && (
  378.                             <li>MIME: {fileInfo.file.type}</li>)}
  379.                         <li>Size: {fileInfo.file.size} bytes</li>
  380.                         <li>Type: {getCreatedTypeName()}</li>
  381.                     </ul>
  382.  
  383.                 </section>
  384.             )}
  385.  
  386.             {fileInfo && (
  387.                 <>
  388.                     <button onClick={generateContentFile}
  389.                         className="submit"
  390.                     >Download header file</button><br />
  391.                     <button
  392.                         onClick={generateContentClip}
  393.                         className="submit"
  394.                     >Copy to clipboard</button>
  395.                     <a ref={downloadLinkRef} href={downloadUrl} download={getDownloadName(ident, genType)} hidden></a>
  396.                 </>
  397.             )}
  398.         </div>
  399.     );
  400. };
  401.  
  402. export default HeaderGenerator;
  403.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement