File "xdata.inc"
Path: /nimoworld/inc/xdata.inc
File size: 7.7 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 GetSharedData() ' sharedData() needs to be DIMed before calling this sub
LOCAL i0, i1, i AS LONG
i0 = LBOUND(sharedData)
i1 = UBOUND(sharedData)
REDIM PRESERVE sharedData(i0 TO i1)
DIM xd(i0 TO i1) AS ExeData
ParseExeData EXE.FULL$, xd()
IF UBOUND(xd) > 0 THEN ' found some ExeData in the current executable
DIM iXD(i0 TO i1) AS LONG ' indexes to the ExeData chunks
FOR i = i0 TO i1
iXD(i) = FindExeData(FORMAT$(i,"000"), xd())
IF iXD(i) > 0 THEN sharedData(i) = GetExeData( EXE.FULL$, xd(iXD(i)) )
NEXT
END IF
END SUB
'--------------------------------------------------------------------------------
'--------------------------------------------------------------------------------
FUNCTION Exist(BYVAL fileOrFolder AS STRING) AS LONG
LOCAL Dummy&
Dummy& = GETATTR(fileOrFolder)
FUNCTION = (ERRCLEAR = 0)
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
'--------------------------------------------------------------------------------