Author Topic: Little tool to mark QB64 compiled EXE's with it size, for appending data.  (Read 5556 times)

0 Members and 1 Guest are viewing this topic.

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
This is something I've been using to help with appending data to my EXE's.  Seems to work with no problems, thought I'd share it.  It basically marks the EXE with its EXE file size, so my program can read that info and know where the appended data begins.  It shortens "This program cannot be run in DOS mode." to "This program can't run in DOS mode.", and uses the gained spaces to save the EXE size.

It works for me in QB64-32bit compiled programs.  Have not tested it in 64-bit at all.  Use at your own risks, as it overwrites EXE data. 

Mark your EXE's BEFORE you append data to it.

- Dav

Code: QB64: [Select]
  1. '===============
  2. 'MarkExeSize.bas
  3. '===============
  4. 'Marks QB64 compiled EXE's with its EXE data size.
  5. 'Coded by Dav, JAN/2021
  6.  
  7. 'WINDOWS ONLY!
  8.  
  9. 'This helps facilitate using appended data on the EXE.
  10. 'It saves the compiled EXE size to the EXE file, so
  11. 'the program can read that info and jump to its data.
  12.  
  13. 'It does this by borrowing some space near the top of
  14. 'the EXE file.  It shortens 'This program cannot be run
  15. 'in DOS mode.' to 'This program can't run in DOS mode.' and
  16. 'uses those 4 gained spaces to save EXE file size instead.
  17.  
  18. '=======================================================
  19. 'Example...after you mark your EXE file, it can do this:
  20. '=======
  21. 'OPEN COMMAND$(0) FOR BINARY AS 1  'Open itself up...
  22. 'test$ = INPUT$(200, 1) 'grab a little info
  23. 'place = INSTR(1, test$, "This program can't") 'look for words
  24. 'IF place = 0 THEN PRINT "No data found.": CLOSE: END
  25. 'grab exesize info...
  26. 'SEEK 1, place + 35: ExeSize& = CVL(INPUT$(4, 1))
  27. 'Go there....
  28. 'SEEK 1, ExeSize& + 1   'where appended data begins
  29. '=======================================================
  30.  
  31. 'NOTE: Always mark the EXE before appending data to it.
  32. '      If you use EXE compressors, like UPX, mark the EXE
  33. '      AFTER using UPX, not before, otherwise the info won't
  34. '      be read correctly by your program.
  35.  
  36.  
  37. SCREEN Pete
  38.  
  39. PRINT "================"
  40. PRINT "MarkExeSize v1.0 - by Dav"
  41. PRINT "================"
  42.  
  43.     INPUT "EXE to Mark -->", exe$
  44.     PRINT
  45.     exe$ = COMMAND$
  46.  
  47. IF exe$ = "" THEN END
  48.     PRINT "File not found.": END
  49.  
  50. OPEN exe$ FOR BINARY AS 1
  51.  
  52. 'find location of place to mark
  53. test$ = INPUT$(200, 1)
  54. place = INSTR(1, test$, "This program can")
  55. IF place = 0 THEN
  56.     PRINT "This file is not markable."
  57.     CLOSE: END
  58.  
  59. 'jump to location
  60. SEEK 1, place
  61. look$ = INPUT$(19, 1) 'grab a little info
  62.  
  63. SELECT CASE look$
  64.     CASE IS = "This program cannot"
  65.         'mark/overwrite exe file info file with new info
  66.         PRINT "Marking file "; exe$
  67.         PRINT
  68.         PRINT "EXE files size:"; LOF(1)
  69.         PRINT "Data start loc:"; LOF(1) + 1
  70.         new$ = "This program can't run in DOS mode." + MKL$(LOF(1))
  71.         PUT 1, place, new$
  72.         PRINT: PRINT "Done."
  73.     CASE IS = "This program can't "
  74.         PRINT "EXE already appears to be marked."
  75.         PRINT
  76.         SEEK 1, place + 35: datastart& = CVL(INPUT$(4, 1))
  77.         PRINT "EXE files size:"; LOF(1)
  78.         PRINT "Data start loc:"; datastart& + 1
  79.         PRINT "Size of data  :"; LOF(1) - datastart&
  80.     CASE ELSE
  81.         PRINT "EXE is not markable."
  82.  
  83.  

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
When I append data to the end of an EXE, I always just count backwards from the length of the data.

For example, I have a CSV text file.  I’d open the EXE, append the data to the end of it, and then write the length of that file as a 4-byte long.

Then, when I need to read that file, I read the last 4 bytes to get the size, then back up that length from the end, and get the data.

GET #1, LOF(1) - 4, data_length
File_data$ = SPACE$(data_length)
GET #1, LOF(1) - 4 - data_length, file_data$

Another file would just go after, with its length after that, until I stored all the files I wanted attached to the EXE.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Yea, that works great too.  I use that way also, when doing one file simple things especially. I have a couple of projects that used a lot of files, so i stored the file pack header and filesize lacation, so went with this way to be more organized.  But your way is the short and sweet method for sure.

Didnt you do a fireside animation with appended data once?

- Dav
« Last Edit: January 31, 2021, 04:56:55 pm by Dav »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Yea, that works great too.  I use that way also, when doing one file simple things especially. I have a couple of projects that used a lot of files, so i stored the file pack header and filesize lacation, so went with this way to be more organized.  But your way is the short and sweet method for sure.

Didnt you do a fireside animation with appended data once?

- Dav

This one: https://qb64.freeforums.net/thread/32/campfire-demo  ;)

It’s also how my singing Christmas tree demo works too.  Song and image are appended to the end of the EXE.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #4 on: February 01, 2021, 02:18:31 am »
Quote
GET #1, LOF(1) - 4, data_length
File_data$ = SPACE$(data_length)
GET #1, LOF(1) - 4 - data_length, file_data$

If a picture file, say, BMP was appended this way it could be saved once again as a BMP file and then use _LOADIMAGE. Yes I know of the other way using base 256 / 64  or base 256 / 128 conversion and storing the data in the BAS file.

It would be nice if QB64 had an instruction that would load a picture file from memory.

So you start with an BMP file appended to an EXE. From there get appended data into some kinda MEM block that returns a handle and then use PUTIMAGE etc.

« Last Edit: February 01, 2021, 02:36:45 am by NOVARSEG »

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #5 on: February 01, 2021, 03:25:27 am »
ROFL @ SCREEN Pete

SCREEN Pete, the only screen mode anyone would ever need!

Pete :D
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #6 on: February 01, 2021, 07:58:14 am »
@Pete:  :)

@NOVARSEG:  Yes, that's an option.  I made a tool for doing that as well, saving and putting mem block images to the EXE.  Only downside is that the data is very large in size.  Here's the code I first came up with before adapting the loader code to load from EXE attachment instead.  These saves/loads external files.

- Dav

This one saves the image to a memdata file, it's width, height, data, and byte size.
Code: QB64: [Select]
  1. INPUT "IMAGE File to load --> ", IN$
  2. INPUT "IDATA file to save --> ", OUT$: IF OUT$ = "" THEN END
  3. 'Load image file to screen mode
  4. SCREEN _LOADIMAGE(IN$, 32): SLEEP 1
  5. wid = _WIDTH: hih = _HEIGHT
  6. DIM m AS _MEM: m = _MEMIMAGE(0)
  7. INDATA$ = SPACE$(m.SIZE)
  8. _MEMGET m, m.OFFSET, INDATA$
  9. INDATA$ = _DEFLATE$(INDATA$)
  10. PRINT: PRINT "Saving image data to file...";
  11. total& = 4 + 4 + 4 + LEN(INDATA$) + 4
  12. PRINT #2, MKL$(wid) + MKL$(hih) + MKL$(LEN(INDATA$)) + INDATA$ + MKL$(total&);
  13.  

This one loads it back...
Code: QB64: [Select]
  1. INPUT "ID File to show --> ", IN$
  2. IF IN$ = "" THEN END
  3. SEEK #1, LOF(1) - 3
  4. total& = CVL(INPUT$(4, 1))
  5. SEEK #1, LOF(1) - total& + 1
  6. wid = CVL(INPUT$(4, 1))
  7. hih = CVL(INPUT$(4, 1))
  8. idlen = CVL(INPUT$(4, 1))
  9. INDATA$ = INPUT$(idlen, 1)
  10. INDATA$ = _INFLATE$(INDATA$)
  11. image& = _NEWIMAGE(wid, hih, 32)
  12. DIM m AS _MEM: m = _MEMIMAGE(image&)
  13. _MEMPUT m, m.OFFSET, INDATA$: _MEMFREE m
  14. SCREEN _NEWIMAGE(wid, hih, 32)
  15. _PUTIMAGE (0, 0), image&
« Last Edit: February 01, 2021, 08:00:52 am by Dav »

Offline Dav

  • Forum Resident
  • Posts: 792
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #7 on: February 01, 2021, 11:27:08 am »
I want to add that Steves way has a great advantage of not being restricted to windows only. So if your projects is for other platforms too, just forget this tool and use the saving a footer method.

- Dav

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #8 on: February 02, 2021, 12:41:33 am »
Can you do something like

DIM handle as long

DIM m AS _MEM: m = _MEMIMAGE(0)    (example from your code)

or


DIM m AS _MEM:    _MEMIMAGE(handle) = m   ?

I'm trying to create a handle from a memory block. I think there has to something more generic like

handle =_HANDLE(m)

or skip the handle altogether because  m has been dimensioned in memory. So there does not have to be a handle for m because the OS is SUPPOSED to know where m is in memory otherwise the DIM is pointless!

m = picture data (say, a 24 bit per pixel BMP, no header just the data)

PUTIMAGE positions , m

For that matter why do we even have to use MEM in this case?

DIM m as string * length of BMP  picture data

PUTIMAGE positions , m
« Last Edit: February 02, 2021, 01:20:49 am by NOVARSEG »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #9 on: February 02, 2021, 01:39:01 am »
What are you talking about??

M =_MEMIMAGE(Handle) <-- there's your handle, right there.

With M =_MEMIMAGE(0), 0 is the handle for the current display.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #10 on: February 02, 2021, 02:43:01 am »
Hi Steve 
Sorry for the rant I need coffee

I want to Use your method of appending picture data to end of EXE and put that appended data into a memory block.

The last step is to use PUTIMAGE but that requires a handle

COPYIMAGE LOADIMAGE NEWIMAGE are the only instructions that return a handle?

COPYIMAGE I dont get
LOADIMAGE only works with files
NEWIMAGE does not refer to a memory block

So how do I obtain a handle for PUTIMAGE?


Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #11 on: February 02, 2021, 02:51:51 am »
With_NEWIMAGE:

Handle =_NEWIMAGE(X, Y, 32)
DIM M AS_MEM: M = _MEMIMAGE(Handle)
'load from file to your memblock -- basically:

temp$ = SPACE$(image_size)
GET #1, data_position, temp$ 'load from drive
_MEMPUT M, M.OFFSET, temp$ 'put to image
_MEMFREE M ‘if not needed anymore.

_PUTIMAGE (whereverX,whereverY), Handle
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #12 on: February 02, 2021, 03:09:13 am »
Thanks Steve. 

If my BMP is 1024*768 is this correct

Handle =_NEWIMAGE(1024,768, 32)

and is handle a LONG?

I'm looking at the whole thread, bit rusty with the MEM stuff
« Last Edit: February 02, 2021, 03:33:59 am by NOVARSEG »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #13 on: February 02, 2021, 03:21:22 am »
Yep. 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline NOVARSEG

  • Forum Resident
  • Posts: 509
    • View Profile
Re: Little tool to mark QB64 compiled EXE's with it size, for appending data.
« Reply #14 on: February 02, 2021, 07:40:33 pm »
Ok im making a BMP picture viewer

Quote
DIM a AS _MEM
DIM handle AS LONG
handle = _NEWIMAGE(1024, 768, 32)
a = _MEMIMAGE(handle)

PRINT a.SIZE

prints  1024 * 768 * 4

but I want to use 24 bit per pixel BMPs. Will  I have to parse the 24 bit BMP picture data to include an extra byte for every 3 bytes of data?

The viewer is not going to use _LOADIMAGE
« Last Edit: February 02, 2021, 07:48:48 pm by NOVARSEG »