These two utilities are designed to bridge the file system and memory via

They were devised to solve a particular problem, and then were never used,
and thus left in this rather raw state. They are the sort of tools I often
find my self drawn to, but end up doing things differently. Maybe some day
someone will find them useful?

All these utilities require two longwords placed on the command line;
floats wont do! So you need some function or command to convert floats to
longs, such as my toolkit command LONG$, which takes an S*BASIC "number"
and converts it to a 4-byte long word (in internal representation).


Loads bytes from a channel into memory

        EX somejob, file, lbytes_exe; LONG$(base) & LONG$(length)
        EX lbytes_exe, somefile; LONG$(base) & LONG$(length)

This takes some file <somefile>, which must be no longer than <length>
bytes, and loads it into memory at <base>.

Note: Separators are important!
Note: Base address should be even!

On its own it doesnt seem like much; the keyword LBYTES does as much
without the hassle. However, here you can add filters to further process
the stream of bytes.

Check out the description of TK2's EX & co commands to see how you can
chain various filters.


        ch = FOP_OVER(somefile)

followed by

        EX somejob, #ch, sbytes_exe; LONG$(base) & LONG$(length)
        EX sbytes_exe, #ch; LONG$(base) & LONG$(length)

This saves a chunk of memory via a channel to a device (probably only
file-type devices).

Note: Separators are important!
Note: Base address should be even!

Simple example:


100 fnm1$ = 'dev4_io_lsb_047_spr'
110 fnm2$ = 'RAM1_tst_spr'
120 :
140 fl = FLEN(\ fnm1$)
150 ad = ALCHP(fl)
160 ERT FEW('dev4_io_lsb_LBYTES_exe', fnm1$; LONG$(ad) & LONG$(fl))
170 SPRW#2; 30, 30, ad
180 :
190 ch = FOP_OVER(fnm2$)
200 ERT FEW("dev4_io_lsb_SBYTES_exe", #ch; LONG$(ad) & LONG$(fl))
210 CLOSE#ch
220 RECHP ad
230 :
240 fl = FLEN(\ fnm2$)
250 ad = ALCHP(fl)
260 ERT FEW('dev4_io_lsb_LBYTES_exe', fnm2$; LONG$(ad) & LONG$(fl))
270 SPRW#1; 30, 30, ad
280 RECHP ad
290 :

Assumes mode GD2 and standard 3-window S*BASIC layout!

Given a sprite called 047_spr in dev4_io_lsb_, the above program gets its
size, reserves sufficient  memory for it, and loads it into that memory
slot. To prove it, it displays the sprite in window#2.

A new, empty file is created on ram1_ and the contents of the same memory
slot is copied to that file via the open channel to it. The file is closed
to finalise, and the memory is released.

To prove that the memory contents was saved, the first part of the
program is repeated with the newly created file, and the contents
displayed in window#1.


This utility is nothing but the combination of LBYTES and SBYTES. Since
most of the code for saving and loading is identical, putting the twain
together is actually less than half the size of the two separate versions
together. However, to instruct the utility to load or save rquires and
extra instruction on the command line: 'H' => LBYTES, and 'I' => SBYTES.

Note: Case is important! Only 'H' or 'I' will do! as these are in fact the
Qdos codes for iof.load (= $48) and (= $49).


Put this file into memory:
   ERT FEW(lsbytes_exe, somefile; LONG$(base) & LONG$(length) & 'H')

where base is where you want to put it, and length is length of somefile

   EX lsbytes_exe, #ch; LONG$(base) & LONG$(length) & 'I'

where #ch is a channel open to some writeable device, to save <length>
bytes from <base>.

Or if youre feeling frisky, try:

Process file via filter and commit to memory:
   EX somefilter, somefile TO lsbytes_exe; LONG$(base) & LONG$(length) & 'H'


Get from memory to file via filter
   EX lsbytes_exe; LONG$(base) & LONG$(length) & 'I' TO somefilter, somefile

Note: Separators are important!
Note: Base address should be even!


The reason for developing these tools was to try out whether I could use
zip-compressed sprites for a project of mine. Zip compresses so much better
than RLE in most cases. However, the tools we have, which are all mainly
(or in large part) C conversions, are far too slow to be of any use. There
are good 68k unzip routines about, but I didnt take it any further as I
lost interest in the said project. Here, though, is a simplified demo of
what I tried:


100 EXT_FN 'VALID%', 'LONG$'
110 :
120 zip$     = ''
130 zipinfo$ = 'win2_arc_zip_zipinfo'
140 funzip$  = 'win2_arc_zip_funzip'
150 lsbytes$ = 'dev4_io_lsb_LSBYTES_exe'
160 :
180 CLS: PRINT'Please wait. This is slow!'
190 ch = FOPEN("history")
200 ERT FEW(zipinfo$, #ch; '-t ' & zip$)
210 INPUT#ch; l$: CLOSE#ch
220 IF NOT ('1' INSTR l$) = 1 THEN
230  PRINT 'Only first file will be processed'
240 END IF
250 p% = ', ' INSTR l$
260 IF p% = 0 OR p% > 10 THEN
270  PRINT 'I dont understand this file!': STOP
280 END IF
290 fl$ = l$(p% + 2 TO p% + 10)
300 IF NOT VALID%(2, fl$) THEN
310  PRINT 'Not a valid file!': STOP
320 END IF
330 :
340 fl  = fl$:          REMark Uncompressed size
350 spr = ALCHP(fl):    REMark Reserve room
360 :
370 REMark Now uncompress and load directly into RAM
380 ERT FEW(funzip$, zip$ TO lsbytes$; LONG$(spr) & LONG$(fl) & 'H' )
390 SPRW#1; 20, 20, spr

You need a copy of the INFOZIP suit to try it out. I included a copy of
047_spr, compressed and uncompressed for you to test.

Yeah, you could say it would have been simpler to just unzip to a file and
then LBYTES the sprite, but originally there was more to it than I can
show here..

Program status

V0.01, pjw, 2018 Jan 06, first try
V0.01, pjw, 2021 Oct 25, packaged. Updated demo routines.

Conditions and DISCLAIMER as per