home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
568a.lha
/
compress.library_v1.0
/
programmers
/
compress_lib.prodoc.pp
/
compress_lib.prodoc
Wrap
Text File
|
1991-11-03
|
15KB
|
283 lines
compress.library
Programmer's Documentation
Version 1.0
(C) 1991 Bryan Ford
This is the programmer's documentation for the compress.library
specification. It may be freely distributed, with or without my own
compress.library, as long as the files listed below remain intact and
unchanged. If you would like to see something changed in or added to the
specification, contact me and I'll try my best to accomodate your needs. I
just don't want incompatible libraries floating around.
These are the files that must be included in the programmers'
distribution:
compress_lib.prodoc (this file)
compress_lib.fd
include (dir)
pragmas (dir)
compress.h
clib (dir)
compress_protos.h
libraries (dir)
compress.h
ainclude (dir)
libraries (dir)
compress.i
The .fd file is for all you die-hard BASIC programmers. :-)
The 'include' directory contains C definition header files modeled
after Commodore's directory structure. 'libraries/compress.h' contains the
general tag definitions need to call the compress.library.
'clib/compress_protos.h' contains prototypes for the compress.library's
functions, and 'pragmas/compress.h' contains function pragmas for SAS/C.
(Sorry, I haven't written any stubs yet. I'm lazy.)
The file 'ainclude/libraries/compress.i' contains the definitions
needed to call the compress.library from assembly language, including the
appropriate LIBDEF's.
There are just three main functions you will need to use in the
compress.library: CompressInfo(), Compress(), and Decompress(). The
function CompressInfo() allows you to obtain various information on the
compress.library, while the Compress() and Decompress() functions perform
the actual compression and decompression operations.
Most compress.library functions use TagItem arrays (tag lists) as
defined in the include files for Kickstart 2.0. This does not necessarily
mean that the compress.library will only work on 2.0. (My implementation,
at least, works under pre-2.0.)
CompressInfo()
~~~~~~~~~~~~~~
The first function, CompressInfo(), accepts a pointer (in A0) to a
tag list which you must create, and fills it in with information about the
compress.library. The tags for this function are defined in
libraries/compress.(h|i). Basically, you create a TagItem array and
initialize the ti_Tag field of each to specify the information you want,
then call CompressInfo() with the tag list, and when it returns, your
TagItem array has been filled in with appropriate information. Not all of
the tags may be supported in a given compress.library. Therefore, you must
initialize all your ti_Data fields in your tag list to 0 before calling
CompressInfo(), and be prepared to find values of 0 in the array after the
call.
Most of the information available through CompressInfo() is pretty
much self-explanatory. The CS_xxxName tags return pointers to strings
within compress.library's memory space. These will remain valid at least
until CloseLibrary(). The ProgramName is the name of the library or
implementation, the AuthorName is the name of the programmer that created
the library, and the AlgoName tells briefly what algorithm the library
uses. These three names are intended for user information only, and should
not be interpreted by a program in any way.
The CompSpeed and DecompSpeed fields allow the application to get
an idea of how fast the compressor and decompressor are. When the library
is first loaded, the compress.library should run a very brief benchmark of
some kind to find out how fast compression and decompression go on the
machine it's running on. Then, after each call of Compress() or
Decompress(), the estimated value should be updated (probably with a
combination of the new value and the previous value, to average the
estimate over multiple runs).
The CS_AsyncComp and CS_AsyncDecomp tags are used by a program to
determine whether or not the compress.library supports the asynchronous
compression function calls. Unless the compress.library returns a nonzero
value in these tag, the alternate function entrypoints must be assumed to
not exist. The asynchronous function calls are described in detail later.
The CS_BlockComp and CS_BlockDecomp tags are used to determine
whether or not the compress.library supports multiblock compression and
decompression requests. These flagf work the same way as CS_AsyncComp and
CS_AsyncDecomp. Multiblock operations are described in detail later.
Single-block Compression
~~~~~~~~~~~~~~~~~~~~~~~~
To actually compress and decompress data, a program must call the
Compress() and Decompress() functions. As with CompressInfo(), they both
accept pointers to TagItem arrays (in A0). However, in this case, *you*
must initialize the ti_Data fields in the array, and the Compress() and
Decompress() functions do not change them.
To compress a block of data, you must pass Compress() a tag list
with at least three items: the input data (CS_InputBuffer), the size of
the input data (CS_InputSize), and a buffer to write the compressed data
into. The output buffer must be AT LEAST as large as the input buffer.
Also, both the input buffer and the output buffer must be longword aligned.
When you have these fields set up, just call Compress(). If the
compression is successful, it will return a positive number indicating the
number of bytes used in the destination buffer. If you write the buffer to
disk or copy it somewhere else, you must copy at least this number of bytes
starting at the beginning of the output buffer you supplied. Also, no
matter how much of the output data you actually store (you might want to
store an integral number of longwords or something), you must remember the
EXACT number of output bytes returned to pass to the Decompress() function.
If the compression failed, a negative error value is returned (one of
CSERR_xxxx). Common failures are CSERR_NOMEMORY (not enough memory) and
CSERR_NOCOMPRESSION (the data is uncompressible with this algorithm).
When you want to decompress a block of data you previously
compressed, you must call Decompress(). Again, you must pass it a tag list
with at least three items: the input buffer with the compressed data
(CS_InputBuffer), the number of bytes used in the input buffer
(CS_InputSize), and a pointer to the output buffer (CS_OutputBuffer). The
CS_InputSize that you pass must be the EXACT same value (not rounded up or
anything) that was returned by Compress(). Also, CS_OutputBuffer must be
at least the size of the input data you originally gave to Compress().
Therefore, along with any compressed data, you will also have to store the
original (decompressed) size, so you can allocate a big enough block later,
and the exact compressed size. Decompress() returns the final decompressed
size (you should make sure it's equal to the size you originally gave to
Compress()), or else a negative error code if the call failed. Common
errors for Decompress are CSERR_NOMEMORY (not enough memory) and
CSERR_INCOMPATIBLE (the block was compressed with a different, incompatible
compress.library). A decompressor must always be able to recognize its own
type of compressed data, and must return CSERR_INCOMPATIBLE if a call is
made to decompress an unknown data format.
Optional Features
~~~~~~~~~~~~~~~~~
Besides the standard three-function compression available in any
compress.library, libraries have the option of supporting some extended
features. These features may not be relied on by applications (they must
check first with CompressInfo() to make sure the features are available).
Currently the only two extended features defined are asynchronous
compression/decompression, and blocked data streams.
The method of compression - normal, asynchronous, blocked,
asynchronous blocked, etc. - should not affect the format of the
compressed data. Therefore, a program should be able to compress some data
in one mode and decompress it in another.
Note that, as of this version of this document, my compress.library
supports neither of these extended features. Don't worry though - it will
soon.
Asynchronous Processing
~~~~~~~~~~~~~~~~~~~~~~~
If a previous call to CompressInfo() returned nonzero in a
CS_AsyncSupport tag, an extended set of compression and decompression
functions is available which allows the program to start a compression
operation, and have it complete in the background, thereby allowing the
program to keep responding to events such as user interaction. (i.e. the
program doesn't "freeze" while it's working on data.) Remember that a
compress.library may support asynchronous compression but not asynchronous
decompression, or vice versa: don't assume that because it supports one,
it also supports the other.
To use this feature, simply call the CompressStart() or
DecompressStart() functions just as you would Compress() or Decompress().
However, instead of returning when the operation is finished, these
functions return immediately (or very soon at least). Instead of returning
the final size or error code, these functions return a handle, which could
be anything - you should just treat it as a longword value. Null may be a
valid return handle for these functions - you should not NOT check for null
return codes here. All errors will be returned from the CompressEnd()
function. Any call to one of these functions must be paired with one call
to CompressEnd(), below. After the function returns, you can go about your
business, as long as your business doesn't involve touching the input or
output buffers you gave the function.
You may periodically check to see if an operation is finished by
calling CompressCheck() with the handle in d0. The function will return
nonzero (true) if the operation is finished or zero (false) if it is still
in progress.
When your program is ready and needs the results of the compression
or decompression operation, it should call CompressEnd() with the handle in
D0. If the operation had already finished, this function will return very
quicky. If the operation is still in progress, it will Wait() until it
finishes. After this function returns, the handle is no longer valid.
This function returns the final results of the operation just like the
normal Compress() or Decompress() function calls would.
If you need to know exactly when a compression operation finishes,
you may put another tag, CS_AsyncMsg, into the tag list you send to the
CompressStart() or DecompressStart() call. The ti_Data field must point to
a valid Exec Message structure. When the operation is complete, the
message will be ReplyMsg()'d. Note that this message, if given, will
ALWAYS be replied, even on a failure. If you call CompressEnd() before the
operation is finished and it must wait for it to complete, the message will
still be replied at the end of the operation just before returning.
Blocked Data
~~~~~~~~~~~~
Compressing single memory blocks at a time is fine for small pieces
of data, or if you have plenty of memory. However, memory tends to quickly
run out if you start compressing large streams of data. It is often much
more convenient and memory-efficient to work with the source and
destination data streams on a piece-by-piece basis, copying blocks to and
from disk as needed. The compress.library specification has facilities for
blocked data in compression and decompression (although libraries don't
necessarily have to support it). Applications must be able to fall back on
simple one-piece compression if the compress.library they're trying to use
doesn't support blocked data streams. (Usually this can be handled by
simply dividing the data into several independently compressed pieces.)
Before trying to use blocked data in compression or decompression,
the application must first make sure the library supports it by calling
CompressInfo() and requesting the CS_BlockComp and/or CS_BlockDecomp flags,
depending on the needs. (Remember to initialize the ti_Data fields to
zero.) If the flag remains zero, the application must not try to use
blocked data.
To use blocked data during compression or decompression, instead of
providing CS_InputBuffer, CS_InputSize, and CS_OutputBuffer in the tag
list, the program simply supplies the tag CS_IOHook which points to a
standard Hook structure as defined in "utility/hooks.h". (Although this
structure was introduced in Kickstart 2.0, 2.0 is not necessarily required
to use the structure.)
During compression, the IOHook will be called whenever more input
data is required, or whenever the output buffer fills up and a new output
buffer is required. The Hook is called using standard Hook calling
conventions, with A1 pointing to a CompressIOMsg as defined in
"libraries/compress.h". The first longword, Command, the library fills in
to tell the hook routine what to do. Currently it may be only
CIOMC_NEXTSOURCE, requesting a new bufferful of source data, or
CIOMC_NEXTDEST, requesting a new empty destination buffer. The hook
routine must then fill in the BlockPtr and BlockSize fields of the message
with the address and size of a new buffer, and then return 0. If an error
occurs and the hook needs to abort the operation, it can return a negative
return code, and the operation will immediately stop and the return code
will be passed back to the application.
All buffers supplied through the IOHook must be on longword
boundaries, and their size must be evenly divisible by four. The only
exception to this is the very LAST block of source data, where the size may
be anything. After source data runs out, the hook must return 0 on the
next CIOMC_NEXTSOURCE request. During decompression, remember that you
must supply the EXACT number of bytes to the decompressor that the
compressor gave you. Don't supply any extra garbage bytes.
The return code from the Compress() or Decompress() call (or
CompressEnd(), if you're using asynchronous processing) is exactly the same
as it normally is: a negative error code, or the total number of bytes
sent to the destination. After compression, the total destination size can
be used to find the number of bytes used in the last output buffer which,
as I said before, you must know for decompression. (Just subtract the
total number of bytes in previous, complete blocks.)
Contacting Me
~~~~~~~~~~~~~
I can be contacted for comments, suggestions, or flames at any of
the addresses below.
Bryan Ford
27104 Ballif Hall
Salt Lake City, UT 84112
(801) 585-4619
baf0863@cc.utah.edu
baf0863@utahcca.bitnet
Have fun!