Copyright(c) David Kuehling 1998/99 This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution.
shrnklib
for Extraction
shrnklib
shrnklib
. It may also be used by other PC programs for text compressions and similar purposes. When you've allready used other compression libraries such as hufflib
, lzsslib
or pk92lib
you won't have any problems with that library. In fact Shrink92 is superior to all those compression algorithms. It took me over a week to design the Shrink compression. It is a combination of an optimized LZSS, RLE and Huffman compression. As you will see compression is quite slow. But therefore uncompression runs very fast and compression ratios are sometimes almost Winzip - like. In case you already worked with Packer92, please don't judge my programing skills by that program. Packer92 was the first thing I programed for Fargo, it's more than a year ago, I was quite an amateur in these times. To convince you of Shrink92's power, here is a comparison of the most common algorithms, used by TI-92 programmers: (ratio specifies the difference of the original file to the compressed file, thus a greater ratio represents a better compression)
Filename | Size (bytes) | Huffman | LZSS | Packer92 | Shrink92 | |
---|---|---|---|---|---|---|
traps.txt | 5403 | 3390 (ratio: 37.26%) | 2665 (ratio: 50.68%) | 2201 (ratio: 59.26%) | 2141 (ratio: 60.37%) | |
fargo.txt | 47152 | 29220 (ratio: 38.03%) | 21410 (ratio: 54.59%) | 18080 (ratio: 61.66%) | 16286 (ratio: 65.46%) | |
fpl.92p | 2035 | 1902 (ratio: 6.54%) | 1759 (ratio: 13.56%) | 1859 (ratio: 8.65%) | 1774 (ratio: 12.83%) | |
db92.92p | 12882 | 10232 (ratio: 20.57%) | 9534 (ratio: 25.99%) | 8882 (ratio: 31.05%) | 8408 (ratio: 34.73%) | |
bd.92p | 14773 | 10736 (ratio: 27.33%) | 9636 (ratio: 34.77%) | 8465 (ratio: 42.70%) | 8157 (ratio: 44.78%) | |
some 3 plane picture | 11520 | 6812 (ratio: 40.87%) | 7440 (ratio: 35.42%) | 6944 (ratio: 39.72%) | 6370 (ratio: 44.70%) |
As you can see, small files (about 2K) aren't compressed very efficent. This can be compensated by putting many small files into one archive. The structure of Shrink92 archives allows single files to be uncompressed without scanning through the rest of the archive, although different files in one archive partially use same compression data, thus optimize the total compression ratio. Shrink92 is also capable of creating an include file that will help you to access the archive.
SHRINK92 file1 [file2] ... [-iinclude-file] [-ooutput-file] [-v] [-m]
EQU
ate for each file. This EQU
ate contains the relative offset of that file within archive section #0, where all the files are stored. Example: You compressed picture1.raw
and picture2.raw
with the -m option and created an include file. This include file contains the two EQU
ates PICTURE1.RAW
and PICTURE2.RAW
. After you extracted archive section #0 that contains these two files, A0
pointes to the memory region where the two extracted pictures are. You may now access each single picture by PICTURE1.RAW(a0)
and PICTURE2.RAW(a0)
(of course you will have to INCLUDE
the include file that you've created).
shrnklib
for Extractionshrnklib
library contains only 3 routines:
shrnklib::OpenArchive
A0
for access, returns an archive descriptor handle in D0
. That archive descriptor contains some compression data that only need to be extracted once - it would be inefficent to extract them for each file again. The archive descriptor also contains the pointer to the archive data. For this reason you only need D0
for specifying the archive you want to access. A0
isn't required any more.
shrnklib::CloseArchive
D0
. This will free all memory that is used by the archive descriptor. The handle becomes invalid.
shrnklib::Extract
D1
, of the archive whose descriptor handle is given by D0
. You may specify the destination in memory where to extract the data to by A0
. If you set A0
to zero shrnklib::Extract
will automatically allocate sufficient memory and return the handle of the allocated block in D2
and it's address in A0
.
shrnklib.h
.
EVEN
before the the label that's used to address the archive.
shrnklib
doesn't. I will perhaps add support for great archive sections in a future version...
shrinklib
, use the -v option when compressing the files. This will make Shrink92 to verify the archive's contents. In case that the created archive is somehow wrong (the uncompressed archive doesn't match the source) you'll get an error message. Please contact me if this happens.
shrnklib
gray7lib
library. The 3 planes are given separated in the files picture0.1pl
, picture1.1pl
and picture2.1pl
. To display the picture these planes have to be put to the equivalent planes of gray7lib
. I gained that pictures by converting a .TGA
file by UGPConv and separating the planes by a hex editor, however this is irrelevant for that example. Note that I didn't optimized the example programs very much, since I wanted to make them as overviewing as possible. First of all I want to show you how the program would look like if you didn't compress the pictures:
INCLUDE "flib.h"
INCLUDE "gray7lib.h"
XDEF _main
XDEF _comment
;-----------------------------------------------------------------------------
; Copy one plane (3840 bytes) from (a1) to (a2)
;-----------------------------------------------------------------------------
CopyPlane:
move.w #3840/4-1,d7 ; d7 is our counter
\Loop: move.l (a1)+,(a2)+
dbra d7,\Loop ; loop back until d7 reaches -1
rts
;-----------------------------------------------------------------------------
; MAIN
;-----------------------------------------------------------------------------
_main: jsr gray7lib::on ; switch 7 shade grayscale on
tst.l d0 ; if d0.l = zero: failure
beq \Error
; copy plane #2 to gray7lib::plane2
lea Plane2(PC),a1 ; load address of source plane
movea.l gray7lib::plane2,a2 ; load destination address
bsr CopyPlane ; copy the plane from (a1) to (a2)
; copy plane #1 to gray7lib::plane1
lea Plane1(PC),a1 ; load address of source plane
movea.l gray7lib::plane1,a2 ; load destination address
bsr CopyPlane ; copy the plane from (a1) to (a2)
; copy plane #0 to gray7lib::plane0
lea Plane0(PC),a1 ; load address of source plane
movea.l gray7lib::plane0,a2 ; load destination address
bsr CopyPlane ; copy the plane from (a1) to (a2)
jsr flib::idle_loop ; wait for keypress
jsr gray7lib::off ; disable 7 shade grayscale
\Error: rts ; exit program
; here are the 3 planes, added binary to the program
EVEN
Plane0: INCBIN "picture0.1pl"
Plane1: INCBIN "picture1.1pl"
Plane2: INCBIN "picture2.1pl"
_comment: dc.b "Displays an uncompressed pic",0
END
Now we move on to the first possiblity to compress the data: Creating an archive with 3 sections, each section containing one plane. Section #0 will contain plane #0, section #1 will contain plane #1 and so on. To do the compression, type the following from the DOS command line:
shrink92 picture?.1pl -oarchive1.shk -iarchive1.inc
This will create an archive named archive1.shk
, containing the planes. Note: if you're using wildcards like the ? in the above example the files will be loaded in alphabetical order. The include file archive1.inc
that is also created will consist of EQU
ates that contain the number of the section each file is stored in, and each section's length:
archive1.inc
;=============================================================================
; Include file automatically created by SHRINK92 Fri Jan 8 09:09:35 1999
; Purpose: access of archive `archive.shk'
; That archive consists of 3 files in 3 sections.
;=============================================================================
PICTURE0.1PL EQU 0 ; index of archive section
PICTURE0.1PL_LEN EQU 3840 ; length of file
PICTURE1.1PL EQU 1 ; index of archive section
PICTURE1.1PL_LEN EQU 3840 ; length of file
PICTURE2.1PL EQU 2 ; index of archive section
PICTURE2.1PL_LEN EQU 3840 ; length of file
Displaying the pictures is now very simple: Each section has to be extracted to the corresponding gray plane of gray7lib
. The section, whose index is given by the EQU
ate PICTURE0.1PL
has to be uncompressed to gray7lib::plane0
, the section, specified by PICTURE1.1PL
to gray7lib::plane1
and so on. The resulting program will look like:
examp1e1.asm
INCLUDE "flib.h"
INCLUDE "gray7lib.h"
INCLUDE "shrnklib.h"
; include file that was automatically created by Shrink92
INCLUDE "archive1.inc"
XDEF _main
XDEF _comment
_main: jsr gray7lib::on ; switch 7 shade grayscale on
tst.l d0 ; if d0.l = zero: failure
beq \Error
; open the archive
lea Archive(PC),a0 ; load addresss of archive into a0
jsr shrnklib::OpenArchive ; return: d0.w = archive descriptor handle
; extract plane #2 of picture
moveq #PICTURE2.1PL,d1 ; d1 = index of archive section to extract
movea.l gray7lib::plane2,a0 ; extraction destination is plane #2
jsr shrnklib::Extract ; do the extraction
; extract plane #1 of picture
moveq #PICTURE1.1PL,d1 ; d1 = index of archive section to extract
movea.l gray7lib::plane1,a0 ; extraction destination is plane #1
jsr shrnklib::Extract ; do the extraction
; extract plane #0 of picture
moveq #PICTURE0.1PL,d1 ; d1 = index of archive section to extract
movea.l gray7lib::plane0,a0 ; extraction destination is plane #0
jsr shrnklib::Extract ; do the extraction
jsr shrnklib::CloseArchive ; close the archive whose handle is given
; by d0 (d0 is still the descriptor handle)
jsr flib::idle_loop ; wait for keypress
jsr gray7lib::off ; disable 7 shade grayscale
\Error: rts ; exit program
; shrink archive containing the 3 planes in 3 archive sections
Archive: INCBIN "archive1.shk"
_comment: dc.b "Shrink92 Example #1",0
END
After the archive has been opened by shrnklib::OpenArchive
, d0
will be the archive descriptor handle. During the extraction the value of d0
isn't modified any more, since it is required as input for the shrnklib::Extract
and the shrnklib::CloseArchive
routine (look shrnklib.h
). The rest of the program should be self explaining. This method of compressing each plane of a picture into a separated archive section needs very few memory. 7680 bytes for 7 shade grayscale, about 1.2 K temporarily during the shrnklib::OpenArchive
routine, and 1-2K are used by the archive descriptor handle.
When I said that this was the first possiblity then there's of course a second one. This one needs a little more memory but the archive is in most cases smaller. In this case we put all planes into one archive section. So we have one great archive section instead of 3 small ones. That's why in most cases the compression ration is better. Unfortunately I chose the example pictures picture0.1pl
- picture2.1pl
very badly - they became a little greater when using that method :-(. But remember that this is only an example, normaly files will become smaller. To put all files into one section you'll have to use the -m option. This will make Shrink92 to merge the input files before creating the archive. Type the following from the command line:
shrink92 picture?.1pl -oarchive2.shk -iarchive2.inc -m
When you're using the -m option Shrink92 will create a different kind of include file. Instead of creating one EQU
ate for each file, that contains the index of the section the file is stored in, Shrink92 will create one EQU
ate for each file that contains the offset of that file within archive section #0, where all files are contained in. In the current example the include file looks like:
archive2.inc
;=============================================================================
; Include file automatically created by SHRINK92 Fri Jan 8 09:43:48 1999
; Purpose: access of archive `archive2.shk'
; That archive consists of 3 files in 1 section.
;=============================================================================
PICTURE0.1PL EQU 0 ; offset of file in archive section #0
PICTURE0.1PL_LEN EQU 3840 ; length of file
PICTURE1.1PL EQU 3840 ; offset of file in archive section #0
PICTURE1.1PL_LEN EQU 3840 ; length of file
PICTURE2.1PL EQU 7680 ; offset of file in archive section #0
PICTURE2.1PL_LEN EQU 3840 ; length of file
This means that after we have extracted section #0, and a0
points to the extracted data, we may access the planes separated by PICTURE0.1PL(a0)
up to PICTURE2.1PL(a0)
. To uncompress section #0 we need a memory block of 11520 bytes (size of one plane * 3). If we don't want to allocate it ourselves we can make shrnklib::Extract
to do it for us, by setting the destination pointer a0
to zero. In that case shrnklib::Extract
will return the handle of the allocated memory block in d2
and the pointer in a0
. Here is the program's source:
examp1e1.asm
INCLUDE "tios.h"
INCLUDE "flib.h"
INCLUDE "gray7lib.h"
INCLUDE "shrnklib.h"
; include file that was automatically created by Shrink92
INCLUDE "archive2.inc"
XDEF _main
XDEF _comment
;-----------------------------------------------------------------------------
; Copy one plane (3840 bytes) from (a1) to (a2)
;-----------------------------------------------------------------------------
CopyPlane:
move.w #3840/4-1,d7 ; d7 is our counter
\Loop: move.l (a1)+,(a2)+
dbra d7,\Loop ; loop back until d7 reaches -1
rts
;-----------------------------------------------------------------------------
; MAIN
;-----------------------------------------------------------------------------
_main: jsr gray7lib::on ; switch 7 shade grayscale on
tst.l d0 ; if d0.l = zero: failure
beq \Error
; open the archive
lea Archive(PC),a0 ; load addresss of archive into a0
jsr shrnklib::OpenArchive ; return: d0.w = archive descriptor handle
; extract section #0 that contains all planes
moveq #0,d1 ; d1 = index of archive section to extract
movea.l #0,a0 ; a0 = 0: 'Extract' has to allocate memory
jsr shrnklib::Extract ; do the extraction
; ->a0.l points to allocated extraction memory
; ->d2.l is the handle of that memory block
jsr shrnklib::CloseArchive ; close the archive whose handle is given
; by d0 (d0 is still the descriptor handle)
; copy plane #2 to gray7lib::plane2
lea PICTURE2.1PL(a0),a1 ; load address of plane within extracted block
movea.l gray7lib::plane2,a2 ; load destination address
bsr CopyPlane ; copy the plane from (a1) to (a2)
; copy plane #1 to gray7lib::plane1
lea PICTURE1.1PL(a0),a1 ; load address of plane within extracted block
movea.l gray7lib::plane1,a2 ; load destination address
bsr CopyPlane ; copy the plane from (a1) to (a2)
; copy plane #0 to gray7lib::plane0
lea PICTURE0.1PL(a0),a1 ; load address of plane within extracted block
movea.l gray7lib::plane0,a2 ; load destination address
bsr CopyPlane ; copy the plane from (a1) to (a2)
; free the memory that was allocated for extracting section #0
move.w d2,-(a7) ; d2 is still the handle (look shrnklib::Extract)
jsr tios::HeapFree
addq.l #2,a7
jsr flib::idle_loop ; wait for keypress
jsr gray7lib::off ; disable 7 shade grayscale
\Error: rts ; exit program
; shrink archive containing the 3 planes in 1 archive section
Archive: INCBIN "archive2.shk"
_comment: dc.b "Shrink92 Example #2",0
END
Ok, that's it. I hope you understood everything. Just a little note on the examples: You'll perhaps have to specify absolute include paths for INCLUDE
and INCBIN
. If you want to recompile the example files, included with Shrink92, you'll need to change the include paths in those files.
SHRINK.C
SHRINK92.C
SHRINK.C
.
SHRINK.H
SHRINK.C
.
shrnklib
, please send me a copy of it, no matter if it seems to be good!