home *** CD-ROM | disk | FTP | other *** search
- 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!
-