File "xdata.inc"

Path: /program cloner/inc/xdata.inc
File size: 6.65 KB
MIME-type:
Charset: utf-8

'--------------------------------------------------------------------------------
' An 'ExeData' is a chunk of data at the end of an executable, it can be added
' at runtime. Its structure is: [CHUNK OF DATA][CHUNK SIZE][CHUNK DESC][MAGIC]
' where:
' - CHUNK OF DATA is any blob of data, text or binary
' - CHUNK SIZE is the hexadecimal length (on 8 bytes) of this blob of data
' - CHUNK DESC is a descriptor (on 3 bytes) of this blob of data, it can be
'   anything such as: JPG, CFG, TXT, WAV etc.
' - MAGIC is the ExeData magic value: "{ExDt}"
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
TYPE ExeData
  address AS DWORD
  length  AS DWORD
  desc    AS ASCIIZ * 4
END TYPE
'--------------------------------------------------------------------------------
$EXEDATA_MAGIC = "{ExDt}"
'--------------------------------------------------------------------------------
GLOBAL sharedData() AS STRING ' when packaging a custom widget
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
SUB ParseExeData(BYVAL file AS STRING, BYREF ExDt() AS ExeData)
' Parse an executable and fill the info of its ExeData() parts
    LOCAL a AS STRING
    LOCAL i, n AS LONG

    IF NOT Exist(file) THEN EXIT SUB ELSE a = GetFile(file)
'    LogMe "<Parsing ExeData of file "+file+" ("+FORMAT$(LEN(a),"#,")+" Bytes)"

    WHILE RIGHT$(a, LEN($EXEDATA_MAGIC)) = $EXEDATA_MAGIC
        INCR n
        IF ISFALSE ARRAYATTR(ExDt(),0) THEN ' Array not DIMensioned
            DIM ExDt(1 TO 1)
        ELSE
            REDIM PRESERVE ExDt(1 TO UBOUND(ExDt)+1)
        END IF
        i = UBOUND(ExDt)
        a = LEFT$(a, -LEN($EXEDATA_MAGIC))        ' magic value
        ExDt(i).desc = RIGHT$(a, 3) + $NUL
        a = LEFT$(a, -3)                          ' descriptor (3 Bytes)
        ExDt(i).length = VAL("&H0"+RIGHT$(a,8))
        a = LEFT$(a, - (ExDt(i).length + 8))      ' length (8 Bytes)
        ExDt(i).address = LEN(a) + 1
'        LogMe "- Found a chunk of data, of type '"+ExDt(i).desc _
'             +"', at address "+FORMAT$(ExDt(i).address,"#,")+" (" _
'             +"length: "+FORMAT$(ExDt(i).length,"#,")+" Bytes)"
    WEND

    FOR i = 1 TO UBOUND(ExDt) \ 2  ' sort 'ExeData' array
        IF i = UBOUND(ExDt) / 2 THEN EXIT FOR
        SWAP ExDt(i).desc, ExDt(UBOUND(ExDt)-i+1).desc
        SWAP ExDt(i).length, ExDt(UBOUND(ExDt)-i+1).length
        SWAP ExDt(i).address, ExDt(UBOUND(ExDt)-i+1).address
    NEXT
'    LogMe FORMAT$(n)+" chunk(s) of data found>"

END SUB
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION ClearExeData(BYVAL file AS STRING) AS STRING
' Return the 'exe' part of an executable, w/o any of its ExeData
    LOCAL a  AS STRING
    LOCAL ln AS DWORD

    IF NOT Exist(file) THEN EXIT FUNCTION ELSE a = GetFile(file)
'    LogMe "<Clearing ExeData from file "+file+" ("+FORMAT$(LEN(a),"#,")+" Bytes)"

    WHILE RIGHT$(a, LEN($EXEDATA_MAGIC)) = $EXEDATA_MAGIC
        a = LEFT$(a, - (LEN($EXEDATA_MAGIC) + 3)) ' remove magic value + 3B descriptor
        ln = VAL("&H0"+RIGHT$(a,8))
        a = LEFT$(a, - (ln + 8))                  ' remove 8B length + data blob
    WEND
    FUNCTION = a
'    LogMe "Done. Clean file is "+FORMAT$(LEN(a),"#,")+" Bytes>"

END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION FindExeData(BYVAL desc AS STRING, BYREF ExDt() AS ExeData, _
         OPTIONAL BYVAL start AS LONG) AS LONG
' Return the ExeData() index containing descriptor 'desc' ; or 0 if not found
    LOCAL st, i AS LONG
    IF start > 1 THEN st = start ELSE st = 1
    FUNCTION = 0
    FOR i = st TO UBOUND(ExDt)
        IF TRIM$(UCASE$(ExDt(i).desc)) = TRIM$(UCASE$(desc)) THEN
            FUNCTION = i
            EXIT FUNCTION
        END IF
    NEXT
END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION GetExeData(BYVAL file AS STRING, BYREF ExDtElt AS ExeData) AS STRING
' Return the ExeData(i) part (data chunk) from the executable 'file'
    LOCAL a  AS STRING
    IF NOT Exist(file) THEN EXIT FUNCTION ELSE a = GetFile(file)
    IF ExDtElt.address + ExDtElt.length > LEN(a) THEN EXIT FUNCTION ' out-of-bound
    FUNCTION = MID$(a, ExDtElt.address, ExDtElt.length)
END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION AddExeData(src AS STRING, desc AS STRING, chunk AS STRING) AS STRING
' Add 'chunk' data of type 'desc' to the exe (or data) 'src' and return the result
    LOCAL a, d  AS STRING

    IF LEN(src) < %MAX_PATH AND MID$(src, 2, 2) = ":\" THEN
        IF NOT Exist(src) THEN EXIT FUNCTION ELSE a = GetFile(src)
'        LogMe "<Adding ExeData to file "+src+" ("+FORMAT$(LEN(a),"#,")+" Bytes)"
    ELSE
        a = src
'        LogMe "<Adding ExeData to unnamed executable ("+FORMAT$(LEN(a),"#,")+" Bytes)"
    END IF
'    LogMe "- Trying to add a chunk of data, of type '"+desc _
'         +"' and length "+FORMAT$(LEN(chunk),"#,")+" Bytes"

    IF LEN(chunk) = 0 OR LEN(desc) > 3 THEN ' empty chunk or illegal descriptor
        FUNCTION = a
'        LogMe "Failed. Original file unchanged>"
        EXIT FUNCTION
    END IF
    a += chunk
    a += HEX$(LEN(chunk),8)
    a += SPACE$(3-LEN(TRIM$(desc))) + TRIM$(desc)
    a += $EXEDATA_MAGIC
    FUNCTION = a
'    LogMe "Done. New file is "+FORMAT$(LEN(a),"#,")+" Bytes>"

END FUNCTION
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
SUB SetFile(dat AS STRING, file AS STRING)
    LOCAL ff AS LONG
    KILL file
    ff = FREEFILE
    OPEN file FOR BINARY ACCESS WRITE LOCK READ AS #ff
      PUT$ #ff, dat
    CLOSE #ff
END SUB
'--------------------------------------------------------------------------------

'--------------------------------------------------------------------------------
FUNCTION GetFile(file AS STRING) AS STRING
    LOCAL ff AS LONG
    LOCAL aa AS STRING
    IF NOT Exist(file) THEN EXIT FUNCTION
    ff = FREEFILE
    OPEN file FOR BINARY ACCESS READ LOCK WRITE AS #ff
      GET$ #ff, LOF(#ff), aa
    CLOSE #ff
    FUNCTION = aa
END FUNCTION
'--------------------------------------------------------------------------------