Author Topic: Embedding Files in Programs (FileToDATA convertor) by RhoSigma  (Read 1023 times)

0 Members and 1 Guest are viewing this topic.

Offline Qwerkey

  • Moderator
  • Forum Resident
  • Posts: 736
Embedding files in programs (FileToDATA convertor)

Author: @RhoSigma
Source: qb64.org Forum
URL: https://www.qb64.org/forum/index.php?topic=790.0
Version: November 17, 2018
Tags: [Data Compression]

Description:
These two programs I use a lot.  These goodies got an complete overhaul and are now using the LZW packer/unpacker, which I've released. So this is a good opportunity to make it available again for everybody.  MakeDATA.bas Create a DATA block out of the given file, so you can embed it in your program and write it back when needed.  The DATAs are written into a .bm file.   MakeCARR.bas will do the whole thing in an array on C/C++ level, rather then in DATAs on the QB64 level. Although it's handling is a bit more tricky, as you get not only a .bm file, but also a .h file, and both must match (ie. the DECLARE LIBRARY path in the .bm must point to the .h), this approach has several advantages.

Both of the following tools require the 'lzwpacker.bm' file.

Source Code MakeDATA.bas:
Code: QB64: [Select]
  1.     '+---------------+---------------------------------------------------+
  2.     '| ###### ###### |     .--. .         .-.                            |
  3.     '| ##  ## ##   # |     |   )|        (   ) o                         |
  4.     '| ##  ##  ##    |     |--' |--. .-.  `-.  .  .-...--.--. .-.        |
  5.     '| ######   ##   |     |  \ |  |(   )(   ) | (   ||  |  |(   )       |
  6.     '| ##      ##    |     '   `'  `-`-'  `-'-' `-`-`|'  '  `-`-'`-      |
  7.     '| ##     ##   # |                            ._.'                   |
  8.     '| ##     ###### |  Sources & Documents placed in the Public Domain. |
  9.     '+---------------+---------------------------------------------------+
  10.     '|                                                                   |
  11.     '| === MakeDATA.bas ===                                              |
  12.     '|                                                                   |
  13.     '| == Create a DATA block out of the given file, so you can embed it |
  14.     '| == in your program and write it back when needed.                 |
  15.     '|                                                                   |
  16.     '| == The DATAs are written into a .bm file together with a ready to |
  17.     '| == use write back FUNCTION. You just $INCLUDE this .bm file into  |
  18.     '| == your program and call the write back FUNCTION somewhere.       |
  19.     '|                                                                   |
  20.     '| == This program needs the 'lzwpacker.bm' file available from here:|
  21.     '| == https://www.qb64.org/forum/index.php?topic=783.0, as it will   |
  22.     '| == try to compress the given source file in order to keep the DATA|
  23.     '| == block as small as possible. If compression is successful, then |
  24.     '| == your program also must $INCLUDE 'lzwpacker.bm' to be able to   |
  25.     '| == decompress the file data again for write back. MakeDATA.bas is |
  26.     '| == printing a reminder message in such a case.                    |
  27.     '|                                                                   |
  28.     '+-------------------------------------------------------------------+
  29.     '| Done by RhoSigma, R.Heyder, provided AS IS, use at your own risk. |
  30.     '| Find me in the QB64 Forum or mail to support[member=111]RhoSigma[/member]-cw.net for  |
  31.     '| any questions or suggestions. Thanx for your interest in my work. |
  32.     '+-------------------------------------------------------------------+
  33.      
  34.     '--- if you wish, set any default paths, end with a backslash ---
  35.     srcPath$ = "" 'source path
  36.     tarPath$ = "" 'target path
  37.     '-----
  38.     IF srcPath$ <> "" THEN
  39.         COLOR 15: PRINT "Default source path: ": COLOR 7: PRINT srcPath$: PRINT
  40.     END IF
  41.     IF tarPath$ <> "" THEN
  42.         COLOR 15: PRINT "Default target path: ": COLOR 7: PRINT tarPath$: PRINT
  43.     END IF
  44.      
  45.     '--- collect inputs (relative paths allowed, based on default paths) ---
  46.     source:
  47.     LINE INPUT "Source Filename: "; src$ 'any file you want to put into DATAs
  48.     IF src$ = "" GOTO source
  49.     target:
  50.     LINE INPUT "Target Basename: "; tar$ 'write stuff into this file (.bm is added)
  51.     IF tar$ = "" GOTO target
  52.     '-----
  53.     ON ERROR GOTO abort
  54.     OPEN "I", #1, srcPath$ + src$: CLOSE #1 'file exist check
  55.     OPEN "O", #2, tarPath$ + tar$ + ".bm": CLOSE #2 'path exist check
  56.     ON ERROR GOTO 0
  57.      
  58.     '--- separate source filename part ---
  59.     FOR po% = LEN(src$) TO 1 STEP -1
  60.         IF MID$(src$, po%, 1) = "\" OR MID$(src$, po%, 1) = "/" THEN
  61.             srcName$ = MID$(src$, po% + 1)
  62.             EXIT FOR
  63.         ELSEIF po% = 1 THEN
  64.             srcName$ = src$
  65.         END IF
  66.     NEXT po%
  67.     '--- separate target filename part ---
  68.     FOR po% = LEN(tar$) TO 1 STEP -1
  69.         IF MID$(tar$, po%, 1) = "\" OR MID$(tar$, po%, 1) = "/" THEN
  70.             tarName$ = MID$(tar$, po% + 1)
  71.             EXIT FOR
  72.         ELSEIF po% = 1 THEN
  73.             tarName$ = tar$
  74.         END IF
  75.     NEXT po%
  76.     MID$(tarName$, 1, 1) = UCASE$(MID$(tarName$, 1, 1)) 'capitalize 1st letter
  77.      
  78.     '--- init ---
  79.     OPEN "B", #1, srcPath$ + src$
  80.     filedata$ = SPACE$(LOF(1))
  81.     GET #1, , filedata$
  82.     CLOSE #1
  83.     rawdata$ = LzwPack$(filedata$, 20)
  84.     IF rawdata$ <> "" THEN
  85.         OPEN "O", #1, tarPath$ + tar$ + ".lzw"
  86.         CLOSE #1
  87.         OPEN "B", #1, tarPath$ + tar$ + ".lzw"
  88.         PUT #1, , rawdata$
  89.         CLOSE #1
  90.         packed% = -1
  91.         OPEN "B", #1, tarPath$ + tar$ + ".lzw"
  92.     ELSE
  93.         packed% = 0
  94.         OPEN "B", #1, srcPath$ + src$
  95.     END IF
  96.     fl& = LOF(1)
  97.     cntL& = INT(fl& / 32)
  98.     cntB& = (fl& - (cntL& * 32))
  99.     '--- .bm include file ---
  100.     OPEN "O", #2, tarPath$ + tar$ + ".bm"
  101.     PRINT #2, "'============================================================"
  102.     PRINT #2, "'=== This file was created with MakeDATA.bas by RhoSigma, ==="
  103.     PRINT #2, "'=== you must $INCLUDE this at the end of your program.   ==="
  104.     IF packed% THEN
  105.         PRINT #2, "'=== ---------------------------------------------------- ==="
  106.         PRINT #2, "'=== If your program is NOT a GuiTools based application, ==="
  107.         PRINT #2, "'=== then it must also $INCLUDE: 'lzwpacker.bm' available ==="
  108.         PRINT #2, "'=== from http://www.qb64.org/forum/index.php?topic=783.0 ==="
  109.     END IF
  110.     PRINT #2, "'============================================================"
  111.     PRINT #2, ""
  112.     PRINT #2, "'====================================================================="
  113.     PRINT #2, "'Function to write the embedded DATAs back to disk. Call this FUNCTION"
  114.     PRINT #2, "'once, before you will access the represented file for the first time."
  115.     PRINT #2, "'After the call always use the returned realFile$ ONLY to access the"
  116.     PRINT #2, "'written file, as the filename was maybe altered in order to avoid the"
  117.     PRINT #2, "'overwriting of an existing file of the same name in the given location."
  118.     PRINT #2, "'---------------------------------------------------------------------"
  119.     PRINT #2, "'SYNTAX: realFile$ = Write"; tarName$; "Data$ (wantFile$)"
  120.     PRINT #2, "'"
  121.     PRINT #2, "'INPUTS: wantFile$ --> The filename you would like to write the DATAs"
  122.     PRINT #2, "'                      to, can contain a full or relative path."
  123.     PRINT #2, "'"
  124.     PRINT #2, "'RESULT: realFile$ --> On success the path and filename finally used"
  125.     PRINT #2, "'                      after applied checks, use ONLY this returned"
  126.     PRINT #2, "'                      name to access the file."
  127.     PRINT #2, "'                   -> On failure this FUNCTION will panic with the"
  128.     PRINT #2, "'                      appropriate ERROR code, you may handle this as"
  129.     PRINT #2, "'                      needed with your own ON ERROR GOTO... handler."
  130.     PRINT #2, "'====================================================================="
  131.     PRINT #2, "FUNCTION Write"; tarName$; "Data$ (file$)"
  132.     PRINT #2, "'--- separate filename body & extension ---"
  133.     PRINT #2, "FOR po% = LEN(file$) TO 1 STEP -1"
  134.     PRINT #2, "    IF MID$(file$, po%, 1) = "; CHR$(34); "."; CHR$(34); " THEN"
  135.     PRINT #2, "        body$ = LEFT$(file$, po% - 1)"
  136.     PRINT #2, "        ext$ = MID$(file$, po%)"
  137.     PRINT #2, "        EXIT FOR"
  138.     PRINT #2, "    ELSEIF MID$(file$, po%, 1) = "; CHR$(34); "\"; CHR$(34); " OR MID$(file$, po%, 1) = "; CHR$(34); "/"; CHR$(34); " OR po% = 1 THEN"
  139.     PRINT #2, "        body$ = file$"
  140.     PRINT #2, "        ext$ = "; CHR$(34); CHR$(34)
  141.     PRINT #2, "        EXIT FOR"
  142.     PRINT #2, "    END IF"
  143.     PRINT #2, "NEXT po%"
  144.     PRINT #2, "'--- avoid overwriting of existing files ---"
  145.     PRINT #2, "num% = 1"
  146.     PRINT #2, "WHILE _FILEEXISTS(file$)"
  147.     PRINT #2, "    file$ = body$ + "; CHR$(34); "("; CHR$(34); " + LTRIM$(STR$(num%)) + "; CHR$(34); ")"; CHR$(34); " + ext$"
  148.     PRINT #2, "    num% = num% + 1"
  149.     PRINT #2, "WEND"
  150.     PRINT #2, "'--- write DATAs ---"
  151.     PRINT #2, "RESTORE "; tarName$
  152.     PRINT #2, "READ numL&, numB&"
  153.     PRINT #2, "rawdata$ = SPACE$((numL& * 4) + numB&)"
  154.     PRINT #2, "stroffs& = 1"
  155.     PRINT #2, "FOR i& = 1 TO numL&"
  156.     PRINT #2, "    READ dat&"
  157.     PRINT #2, "    MID$(rawdata$, stroffs&, 4) = MKL$(dat&)"
  158.     PRINT #2, "    stroffs& = stroffs& + 4"
  159.     PRINT #2, "NEXT i&"
  160.     PRINT #2, "IF numB& > 0 THEN"
  161.     PRINT #2, "    FOR i& = 1 TO numB&"
  162.     PRINT #2, "        READ dat&"
  163.     PRINT #2, "        MID$(rawdata$, stroffs&, 1) = CHR$(dat&)"
  164.     PRINT #2, "        stroffs& = stroffs& + 1"
  165.     PRINT #2, "    NEXT i&"
  166.     PRINT #2, "END IF"
  167.     PRINT #2, "ff% = FREEFILE"
  168.     PRINT #2, "OPEN file$ FOR OUTPUT AS ff%"
  169.     IF packed% THEN
  170.         PRINT #2, "CLOSE ff%"
  171.         PRINT #2, "filedata$ = LzwUnpack$(rawdata$)"
  172.         PRINT #2, "OPEN file$ FOR BINARY AS ff%"
  173.         PRINT #2, "PUT #ff%, , filedata$"
  174.     ELSE
  175.         PRINT #2, "PRINT #ff%, rawdata$;"
  176.     END IF
  177.     PRINT #2, "CLOSE ff%"
  178.     PRINT #2, "'--- set result ---"
  179.     PRINT #2, "Write"; tarName$; "Data$ = file$"
  180.     PRINT #2, "EXIT FUNCTION"
  181.     PRINT #2, ""
  182.     PRINT #2, "'--- DATAs representing the contents of file "; srcName$
  183.     PRINT #2, "'---------------------------------------------------------------------"
  184.     PRINT #2, tarName$; ":"
  185.     '--- read LONGs ---
  186.     PRINT #2, "DATA "; LTRIM$(STR$(cntL& * 8)); ","; LTRIM$(STR$(cntB&))
  187.     tmpI$ = SPACE$(32)
  188.     FOR z& = 1 TO cntL&
  189.         GET #1, , tmpI$: offI% = 1
  190.         tmpO$ = "DATA " + STRING$(87, ","): offO% = 6
  191.         DO
  192.             tmpL& = CVL(MID$(tmpI$, offI%, 4)): offI% = offI% + 4
  193.             MID$(tmpO$, offO%, 10) = "&H" + RIGHT$("00000000" + HEX$(tmpL&), 8)
  194.             offO% = offO% + 11
  195.         LOOP UNTIL offO% > 92
  196.         PRINT #2, tmpO$
  197.     NEXT z&
  198.     '--- read remaining BYTEs ---
  199.     IF cntB& > 0 THEN
  200.         PRINT #2, "DATA ";
  201.         FOR x% = 1 TO cntB&
  202.             GET #1, , tmpB%%
  203.             PRINT #2, "&H" + RIGHT$("00" + HEX$(tmpB%%), 2);
  204.             IF x% <> 16 THEN
  205.                 IF x% <> cntB& THEN PRINT #2, ",";
  206.             ELSE
  207.                 IF x% <> cntB& THEN
  208.                     PRINT #2, ""
  209.                     PRINT #2, "DATA ";
  210.                 END IF
  211.             END IF
  212.         NEXT x%
  213.         PRINT #2, ""
  214.     END IF
  215.     '--- ending ---
  216.     PRINT #2, "END FUNCTION"
  217.     PRINT #2, ""
  218.     CLOSE #2
  219.     CLOSE #1
  220.     COLOR 10: PRINT: PRINT "file successfully processed..."
  221.     COLOR 9: PRINT: PRINT "You must $INCLUDE the created file (target name + .bm extension) at"
  222.     PRINT "the end of your program and call the function 'Write"; tarName$; "Data$(...)'"
  223.     PRINT "in an appropriate place to write the file back to disk."
  224.     IF packed% THEN
  225.         COLOR 12: PRINT: PRINT "Your program must also $INCLUDE 'lzwpacker.bm' available from"
  226.         PRINT "https://www.qb64.org/forum/index.php?topic=783.0 to be able"
  227.         PRINT "to write back the just processed file."
  228.         KILL tarPath$ + tar$ + ".lzw"
  229.     END IF
  230.     done:
  231.     COLOR 7
  232.     END
  233.     '--- error handler ---
  234.     abort:
  235.     COLOR 12: PRINT: PRINT "something is wrong with path/file access, check your inputs and try again..."
  236.     RESUME done
  237.      
  238.     '$INCLUDE: 'lzwpacker.bm'
  239.  
  240.  

Source Code MakeCARR.bas:
Code: QB64: [Select]
  1.     '+---------------+---------------------------------------------------+
  2.     '| ###### ###### |     .--. .         .-.                            |
  3.     '| ##  ## ##   # |     |   )|        (   ) o                         |
  4.     '| ##  ##  ##    |     |--' |--. .-.  `-.  .  .-...--.--. .-.        |
  5.     '| ######   ##   |     |  \ |  |(   )(   ) | (   ||  |  |(   )       |
  6.     '| ##      ##    |     '   `'  `-`-'  `-'-' `-`-`|'  '  `-`-'`-      |
  7.     '| ##     ##   # |                            ._.'                   |
  8.     '| ##     ###### |  Sources & Documents placed in the Public Domain. |
  9.     '+---------------+---------------------------------------------------+
  10.     '|                                                                   |
  11.     '| === MakeCARR.bas ===                                              |
  12.     '|                                                                   |
  13.     '| == Create a C/C++ array out of the given file, so you can embed   |
  14.     '| == it in your program and write it back when needed.              |
  15.     '|                                                                   |
  16.     '| == Two files are created, the .h file, which contains the array(s)|
  17.     '| == and some functions, and a respective .bm file which needs to   |
  18.     '| == be $INCLUDEd with your program and does provide the FUNCTION   |
  19.     '| == to write back the array(s) into any file. All used functions   |
  20.     '| == are standard library calls, no Win API calls are involved, so  |
  21.     '| == this entire thing should work on all QB64 supported platforms. |
  22.     '|                                                                   |
  23.     '| == Make sure to adjust the path for the .h file for your personal |
  24.     '| == needs in the created .bm files (DECLARE LIBRARY), if required. |
  25.     '| == You may specify default paths right below this header.         |
  26.     '|                                                                   |
  27.     '| == This program needs the 'lzwpacker.bm' file available from here:|
  28.     '| == https://www.qb64.org/forum/index.php?topic=783.0, as it will   |
  29.     '| == try to pack the given source file in order to keep the Array(s)|
  30.     '| == as small as possible. If compression is successful, then your  |
  31.     '| == program also must $INCLUDE 'lzwpacker.bm' to be able to unpack |
  32.     '| == the file data again for write back. MakeCARR.bas is printing   |
  33.     '| == a reminder message in such a case.                             |
  34.     '|                                                                   |
  35.     '+-------------------------------------------------------------------+
  36.     '| Done by RhoSigma, R.Heyder, provided AS IS, use at your own risk. |
  37.     '| Find me in the QB64 Forum or mail to support[member=111]RhoSigma[/member]-cw.net for  |
  38.     '| any questions or suggestions. Thanx for your interest in my work. |
  39.     '+-------------------------------------------------------------------+
  40.      
  41.     '--- if you wish, set any default paths, end with a backslash ---
  42.     srcPath$ = "" 'source path
  43.     tarPath$ = "" 'target path
  44.     '-----
  45.     IF srcPath$ <> "" THEN
  46.         COLOR 15: PRINT "Default source path: ": COLOR 7: PRINT srcPath$: PRINT
  47.     END IF
  48.     IF tarPath$ <> "" THEN
  49.         COLOR 15: PRINT "Default target path: ": COLOR 7: PRINT tarPath$: PRINT
  50.     END IF
  51.      
  52.     '--- collect inputs (relative paths allowed, based on default paths) ---
  53.     source:
  54.     LINE INPUT "Source Filename: "; src$ 'any file you want to put into a C/C++ array
  55.     IF src$ = "" GOTO source
  56.     target:
  57.     LINE INPUT "Target Basename: "; tar$ 'write stuff into this file(s) (.h/.bm is added)
  58.     IF tar$ = "" GOTO target
  59.     '-----
  60.     ON ERROR GOTO abort
  61.     OPEN "I", #1, srcPath$ + src$: CLOSE #1 'file exist check
  62.     OPEN "O", #2, tarPath$ + tar$ + ".bm": CLOSE #2 'path exist check
  63.     ON ERROR GOTO 0
  64.      
  65.     '------------------------------------------------------------------------
  66.     '--- NOTE: Depending on the source file's size, one or more array(s)  ---
  67.     '---       are created. This is because some C/C++ compilers seem to  ---
  68.     '---       have problems with arrays with more than 65535 elements.   ---
  69.     '---       This does not affect the write back, as the write function ---
  70.     '---       will take this behaviour into account.                     ---
  71.     '------------------------------------------------------------------------
  72.      
  73.     '--- separate source filename part ---
  74.     FOR po% = LEN(src$) TO 1 STEP -1
  75.         IF MID$(src$, po%, 1) = "\" OR MID$(src$, po%, 1) = "/" THEN
  76.             srcName$ = MID$(src$, po% + 1)
  77.             EXIT FOR
  78.         ELSEIF po% = 1 THEN
  79.             srcName$ = src$
  80.         END IF
  81.     NEXT po%
  82.     '--- separate target filename part ---
  83.     FOR po% = LEN(tar$) TO 1 STEP -1
  84.         IF MID$(tar$, po%, 1) = "\" OR MID$(tar$, po%, 1) = "/" THEN
  85.             tarName$ = MID$(tar$, po% + 1)
  86.             EXIT FOR
  87.         ELSEIF po% = 1 THEN
  88.             tarName$ = tar$
  89.         END IF
  90.     NEXT po%
  91.     MID$(tarName$, 1, 1) = UCASE$(MID$(tarName$, 1, 1)) 'capitalize 1st letter
  92.      
  93.     '--- init ---
  94.     OPEN "B", #1, srcPath$ + src$
  95.     filedata$ = SPACE$(LOF(1))
  96.     GET #1, , filedata$
  97.     CLOSE #1
  98.     rawdata$ = LzwPack$(filedata$, 20)
  99.     IF rawdata$ <> "" THEN
  100.         OPEN "O", #1, tarPath$ + tar$ + ".lzw"
  101.         CLOSE #1
  102.         OPEN "B", #1, tarPath$ + tar$ + ".lzw"
  103.         PUT #1, , rawdata$
  104.         CLOSE #1
  105.         packed% = -1
  106.         OPEN "B", #1, tarPath$ + tar$ + ".lzw"
  107.     ELSE
  108.         packed% = 0
  109.         OPEN "B", #1, srcPath$ + src$
  110.     END IF
  111.     fl& = LOF(1)
  112.     cntL& = INT(fl& / 32)
  113.     cntV& = INT(cntL& / 8180)
  114.     cntB& = (fl& - (cntL& * 32))
  115.     '--- .h include file ---
  116.     OPEN "O", #2, tarPath$ + tar$ + ".h"
  117.     PRINT #2, "// ============================================================"
  118.     PRINT #2, "// === This file was created with MakeCARR.bas by RhoSigma, ==="
  119.     PRINT #2, "// === use it in conjunction with its respective .bm file.  ==="
  120.     PRINT #2, "// ============================================================"
  121.     PRINT #2, ""
  122.     PRINT #2, "// --- Array(s) representing the contents of file "; srcName$
  123.     PRINT #2, "// ---------------------------------------------------------------------"
  124.     '--- read LONGs ---
  125.     tmpI$ = SPACE$(32)
  126.     FOR vc& = 0 TO cntV&
  127.         IF vc& = cntV& THEN numL& = (cntL& MOD 8180): ELSE numL& = 8180
  128.         PRINT #2, "static const unsigned int32 "; tarName$; "L"; LTRIM$(STR$(vc&)); "[] = {"
  129.         PRINT #2, "    "; LTRIM$(STR$(numL& * 8)); ","
  130.         FOR z& = 1 TO numL&
  131.             GET #1, , tmpI$: offI% = 1
  132.             tmpO$ = "    " + STRING$(88, ","): offO% = 5
  133.             DO
  134.                 tmpL& = CVL(MID$(tmpI$, offI%, 4)): offI% = offI% + 4
  135.                 MID$(tmpO$, offO%, 10) = "0x" + RIGHT$("00000000" + HEX$(tmpL&), 8)
  136.                 offO% = offO% + 11
  137.             LOOP UNTIL offO% > 92
  138.             IF z& < numL& THEN PRINT #2, tmpO$: ELSE PRINT #2, LEFT$(tmpO$, 91)
  139.         NEXT z&
  140.         PRINT #2, "};"
  141.         PRINT #2, ""
  142.     NEXT vc&
  143.     '--- read remaining BYTEs ---
  144.     IF cntB& > 0 THEN
  145.         PRINT #2, "static const unsigned int8 "; tarName$; "B[] = {"
  146.         PRINT #2, "    "; LTRIM$(STR$(cntB&)); ","
  147.         PRINT #2, "    ";
  148.         FOR x% = 1 TO cntB&
  149.             GET #1, , tmpB%%
  150.             PRINT #2, "0x" + RIGHT$("00" + HEX$(tmpB%%), 2);
  151.             IF x% <> 16 THEN
  152.                 IF x% <> cntB& THEN PRINT #2, ",";
  153.             ELSE
  154.                 IF x% <> cntB& THEN
  155.                     PRINT #2, ","
  156.                     PRINT #2, "    ";
  157.                 END IF
  158.             END IF
  159.         NEXT x%
  160.         PRINT #2, ""
  161.         PRINT #2, "};"
  162.         PRINT #2, ""
  163.     END IF
  164.     '--- some functions ---
  165.     PRINT #2, "// --- Saved full qualified output path and filename, so we've no troubles"
  166.     PRINT #2, "// --- when cleaning up, even if the current working folder was changed"
  167.     PRINT #2, "// --- during program runtime."
  168.     PRINT #2, "// ---------------------------------------------------------------------"
  169.     PRINT #2, "char "; tarName$; "Name[1056]; // (MAX_PATH * 4) + 16"
  170.     PRINT #2, ""
  171.     PRINT #2, "// --- Cleanup function to delete the written file, called by the atexit()"
  172.     PRINT #2, "// --- handler at program termination time, if requested by user."
  173.     PRINT #2, "// ---------------------------------------------------------------------"
  174.     PRINT #2, "void Kill"; tarName$; "Data(void)"
  175.     PRINT #2, "{"
  176.     PRINT #2, "    remove("; tarName$; "Name);"
  177.     PRINT #2, "}"
  178.     PRINT #2, ""
  179.     PRINT #2, "// --- Function to write the array(s) back into a file, will return the"
  180.     PRINT #2, "// --- full qualified output path and filename on success, otherwise an"
  181.     PRINT #2, "// --- empty string is returned (access/write errors, file truncated)."
  182.     PRINT #2, "// ---------------------------------------------------------------------"
  183.     PRINT #2, "const char *Write"; tarName$; "Data(const char *FileName, int16 AutoClean)"
  184.     PRINT #2, "{"
  185.     PRINT #2, "    FILE *han = NULL; // file handle"
  186.     PRINT #2, "    int32 num = NULL; // written elements"
  187.     PRINT #2, ""
  188.     PRINT #2, "    if (!_fullpath("; tarName$; "Name, FileName, 1056)) return "; CHR$(34); CHR$(34); ";"
  189.     PRINT #2, ""
  190.     PRINT #2, "    if (!(han = fopen("; tarName$; "Name, "; CHR$(34); "wb"; CHR$(34); "))) return "; CHR$(34); CHR$(34); ";"
  191.     PRINT #2, "    if (AutoClean) atexit(Kill"; tarName$; "Data);"
  192.     PRINT #2, ""
  193.     FOR vc& = 0 TO cntV&
  194.         PRINT #2, "    num = fwrite(&"; tarName$; "L"; LTRIM$(STR$(vc&)); "[1], 4, "; tarName$; "L"; LTRIM$(STR$(vc&)); "[0], han);"
  195.         PRINT #2, "    if (num != "; tarName$; "L"; LTRIM$(STR$(vc&)); "[0]) {fclose(han); return "; CHR$(34); CHR$(34); ";}"
  196.         PRINT #2, ""
  197.     NEXT vc&
  198.     IF cntB& > 0 THEN
  199.         PRINT #2, "    num = fwrite(&"; tarName$; "B[1], 1, "; tarName$; "B[0], han);"
  200.         PRINT #2, "    if (num != "; tarName$; "B[0]) {fclose(han); return "; CHR$(34); CHR$(34); ";}"
  201.         PRINT #2, ""
  202.     END IF
  203.     PRINT #2, "    fclose(han);"
  204.     PRINT #2, "    return "; tarName$; "Name;"
  205.     PRINT #2, "}"
  206.     PRINT #2, ""
  207.     '--- ending ---
  208.     CLOSE #2
  209.     CLOSE #1
  210.      
  211.     '--- .bm include file ---
  212.     OPEN "O", #2, tarPath$ + tar$ + ".bm"
  213.     PRINT #2, "'============================================================"
  214.     PRINT #2, "'=== This file was created with MakeCARR.bas by RhoSigma, ==="
  215.     PRINT #2, "'=== you must $INCLUDE this at the end of your program.   ==="
  216.     IF packed% THEN
  217.         PRINT #2, "'=== ---------------------------------------------------- ==="
  218.         PRINT #2, "'=== If your program is NOT a GuiTools based application, ==="
  219.         PRINT #2, "'=== then it must also $INCLUDE: 'lzwpacker.bm' available ==="
  220.         PRINT #2, "'=== from http://www.qb64.org/forum/index.php?topic=783.0 ==="
  221.     END IF
  222.     PRINT #2, "'============================================================"
  223.     PRINT #2, ""
  224.     PRINT #2, "'====================================================================="
  225.     PRINT #2, "'Function to write the array(s) defined in the respective .h file back"
  226.     PRINT #2, "'to disk. Make sure the path in the DECLARE LIBRARY statement does match"
  227.     PRINT #2, "'the actual .h file location. Call this FUNCTION once, before you will"
  228.     PRINT #2, "'access the represented file for the first time. After the call always"
  229.     PRINT #2, "'use the returned realFile$ ONLY to access the written file, don't add"
  230.     PRINT #2, "'any path or extension, as realFile$ is already a full qualified absolute"
  231.     PRINT #2, "'path and filename, which is made by expanding your maybe given relative"
  232.     PRINT #2, "'path and an maybe altered filename in order to avoid the overwriting of"
  233.     PRINT #2, "'an existing file of the same name in the given location. By this means"
  234.     PRINT #2, "'you'll always have easy access to the file, no matter how your current"
  235.     PRINT #2, "'working folder changes during runtime. If requested, the written file"
  236.     PRINT #2, "'can automatically be deleted for you when your program will end, so you"
  237.     PRINT #2, "'don't need to worry about the cleanup yourself. This cleanup feature is"
  238.     PRINT #2, "'implemented on the C/C++ level by using a "; CHR$(34); "atexit()"; CHR$(34); " function."
  239.     PRINT #2, "'---------------------------------------------------------------------"
  240.     PRINT #2, "'SYNTAX: realFile$ = Write"; tarName$; "Array$ (wantFile$, autoDel%)"
  241.     PRINT #2, "'"
  242.     PRINT #2, "'INPUTS: wantFile$ --> The filename you would like to write the array(s)"
  243.     PRINT #2, "'                      to, can contain a full or relative path."
  244.     PRINT #2, "'        autoDel%  --> Shows whether you want the auto cleanup at the"
  245.     PRINT #2, "'                      program end or not (-1 = del file, 0 = don't del)."
  246.     PRINT #2, "'"
  247.     PRINT #2, "'RESULT: realFile$ --> On success the full qualified path and filename"
  248.     PRINT #2, "'                      finally used after applied checks, use ONLY this"
  249.     PRINT #2, "'                      returned name to access the file, don't add any"
  250.     PRINT #2, "'                      path or extension anymore."
  251.     PRINT #2, "'                   -> On failure (write/access) this will be an empty"
  252.     PRINT #2, "'                      string, so you should check for it before trying"
  253.     PRINT #2, "'                      to access the file."
  254.     PRINT #2, "'====================================================================="
  255.     PRINT #2, "FUNCTION Write"; tarName$; "Array$ (file$, clean%)"
  256.     PRINT #2, "'--- declare C/C++ function ---"
  257.     PRINT #2, "DECLARE LIBRARY "; CHR$(34); tarPath$; tar$; CHR$(34); " 'Do not add .h here !!"
  258.     PRINT #2, "    FUNCTION Write"; tarName$; "Data$ (FileName$, BYVAL AutoClean%)"
  259.     PRINT #2, "END DECLARE"
  260.     PRINT #2, "'--- separate filename body & extension ---"
  261.     PRINT #2, "FOR po% = LEN(file$) TO 1 STEP -1"
  262.     PRINT #2, "    IF MID$(file$, po%, 1) = "; CHR$(34); "."; CHR$(34); " THEN"
  263.     PRINT #2, "        body$ = LEFT$(file$, po% - 1)"
  264.     PRINT #2, "        ext$ = MID$(file$, po%)"
  265.     PRINT #2, "        EXIT FOR"
  266.     PRINT #2, "    ELSEIF MID$(file$, po%, 1) = "; CHR$(34); "\"; CHR$(34); " OR MID$(file$, po%, 1) = "; CHR$(34); "/"; CHR$(34); " OR po% = 1 THEN"
  267.     PRINT #2, "        body$ = file$"
  268.     PRINT #2, "        ext$ = "; CHR$(34); CHR$(34)
  269.     PRINT #2, "        EXIT FOR"
  270.     PRINT #2, "    END IF"
  271.     PRINT #2, "NEXT po%"
  272.     PRINT #2, "'--- avoid overwriting of existing files ---"
  273.     PRINT #2, "num% = 1"
  274.     PRINT #2, "WHILE _FILEEXISTS(file$)"
  275.     PRINT #2, "    file$ = body$ + "; CHR$(34); "("; CHR$(34); " + LTRIM$(STR$(num%)) + "; CHR$(34); ")"; CHR$(34); " + ext$"
  276.     PRINT #2, "    num% = num% + 1"
  277.     PRINT #2, "WEND"
  278.     PRINT #2, "'--- write array & set result ---"
  279.     PRINT #2, "Write"; tarName$; "Array$ = Write"; tarName$; "Data$(file$ + CHR$(0), clean%)"
  280.     IF packed% THEN
  281.         PRINT #2, "IF Write"; tarName$; "Array$ <> "; CHR$(34); CHR$(34); " THEN"
  282.         PRINT #2, "    ff% = FREEFILE"
  283.         PRINT #2, "    OPEN Write"; tarName$; "Array$ FOR BINARY AS ff%"
  284.         PRINT #2, "    rawdata$ = SPACE$(LOF(ff%))"
  285.         PRINT #2, "    GET #ff%, , rawdata$"
  286.         PRINT #2, "    filedata$ = LzwUnpack$(rawdata$)"
  287.         PRINT #2, "    PUT #ff%, 1, filedata$"
  288.         PRINT #2, "    CLOSE ff%"
  289.         PRINT #2, "END IF"
  290.     END IF
  291.     PRINT #2, "END FUNCTION"
  292.     PRINT #2, ""
  293.     CLOSE #2
  294.     COLOR 10: PRINT: PRINT "file successfully processed..."
  295.     COLOR 9: PRINT: PRINT "You must $INCLUDE the created file (target name + .bm extension) at"
  296.     PRINT "the end of your program and call the function 'Write"; tarName$; "Array$(...)'"
  297.     PRINT "in an appropriate place to write the file back to disk."
  298.     IF packed% THEN
  299.         COLOR 12: PRINT: PRINT "Your program must also $INCLUDE 'lzwpacker.bm' available from"
  300.         PRINT "https://www.qb64.org/forum/index.php?topic=783.0 to be able"
  301.         PRINT "to write back the just processed file."
  302.         KILL tarPath$ + tar$ + ".lzw"
  303.     END IF
  304.     done:
  305.     COLOR 7
  306.     END
  307.     '--- error handler ---
  308.     abort:
  309.     COLOR 12: PRINT: PRINT "something is wrong with path/file access, check your inputs and try again..."
  310.     RESUME done
  311.      
  312.     '$INCLUDE: 'lzwpacker.bm'
  313.  
  314.