Utilities for reading files compressed with the Lempel-Ziv-Arithmetic
Encoding (LZA) program COMPRESS.EXE:


A number of functions for reading LZA-compressed files and copying them to
uncompressed files are provided in the DOS static link library LZEXPAND.LIB
and the Windows DLL LZEXPAND.DLL.

The Windows functions are available to Control Panel, the Windows part of
Setup, the font installer (FINSTALL.DLL), and other Windows applications and
libraries.


Library Functions:

    Files which are compressed with COMPRESS.EXE are identified by a
    special header.  The functions provided by LZEXPAND.DLL enable an
    application to read either a compressed or an uncompressed file, or to
    copy it to another file (expanding the file if it was compressed).  It
    is possible to read and seek within the source file.  Reading and
    seeking are done directly in an uncompressed file, and in the expanded
    image of a compressed file.

    Files are opened with the normal Windows OpenFile() function.  If seeks
    and / or reads are to be performed, files can be opened with the
    LZOpenFile() function, which creates and initializes the data
    structures used by the other LZ functions.

    The original expanded name of a compressed file can be obtained  using
    GetExpandedName().

    If an entire file is to be copied to a new (expanded) file, the
    LZCopy() function is used.  The input and output files should be opened
    with the Windows OpenFile() function, not LZOpenFile().  The copying
    will still proceed properly if the files are opened with LZOpenFile(),
    but it won't be as fast, since the compressed file is unnecessarily
    buffered through the data structue set up during the call to
    LZOpenFile().  Using LZCopy() is faster for copying purposes than using
    the other functions listed below.  LZCopy(), however, allocates the
    global buffers used upon entrance, and frees them upon exit.

    For copying multiple files consecutively, use LZStart(), CopyLZFile(),
    and LZDone().  LZStart() allocates the global buffers used, and
    LZDone() frees them.  CopyLZFile() works like LZCopy(), but it doesn't
    free the global buffers upon exit.

    If a file is to be read, sequentially or randomly, then the file is
    first opened in one of two ways.  The normal Windows OpenFile()
    function can be used, followed by a call to LZInit() to allocate and
    initialize the data structures used by the expansion algorithm.  The
    file might also be opened by calling LZOpenFile(), which calls
    LZInit().

    LZSeek() and LZRead() may then be used to read the file and seek in it.
    Finally, LZClose() is used to release the data structures and close the
    file.

    The LZInit() function returns either a DOS file handle or an LZFile
    struct identifier of some kind, depending upon how it is called.  The
    LZ functions LZSeek(), LZRead(), and LZClose() needed some way to
    differentiate between DOS file handles and the LZFile struct
    identifiers.  As the functions stand now, they use DOS file handles
    directly and table offsets plus a bias as LZFile identifiers.  The
    table offsets are incremented by a bias value in order to push their
    values past all possible DOS file handle values.  The (table offset -
    bias value) is used as an index into an array of global handles.  So by
    using this table offset, the LZ functions retrieve the appropriate
    global handle to the associated LZFile struct.  The table of global
    handles is allocated statically from the DLL's data segment.  The
    LZFile struct's are allocated from global heap space and are moveable.

    DOS file handles and LZFile struct identifiers can be differentiated.
    DOS file handles are always < the bias value, while LZFile struct
    identifiers are always >= the bias value.  This dichotomy may be used
    in macros, like the sample ones provided in lzexpand.h, to select the
    appropriate function to call (e.g., LZSeek() or _llseek()) in order to
    avoid the overhead of an extra function call for uncompressed files.
    LZSeek(), LZRead(), and LZClose() are, however, "smart" enough to
    figure out whether they are dealing with DOS file handles or table
    offsets, and act appropriately.  As an extreme example, LZOpenFile(),
    LZSeek(), LZRead, and LZClose() can be used as replacements for
    OpenFile(), _llseek(), _lread(), and _lclose, respectively.  In this
    case, the program using the DLL functions could call them without ever
    knowing or caring whether the files it was reading were LZA-compressed
    or not.



LONG FAR PASCAL LZCopy(int doshSource, int doshDest);

    Arguments:  doshSource - source DOS file handle
                doshDest   - destination DOS file handle

    Returns:    LONG - Number of bytes written to output file if sucessful.
                       One of the LZERROR_ codes if unsuccessful.

    Copies file with associated DOS file handle doshSource to file with
    associated DOS file handle doshDest, expanding the data if the source
    file is a compressed file, and returns the output length.

    The destination file is always uncompressed.

    The LONG value returned is the number of bytes actually written to the
    output file, or one of the LZERROR_ codes listed in lzexpand.h and below.

    Both the input and output file should be opened in binary mode.



int FAR PASCAL GetExpandedName(LPSTR lpszSource, LPSTR lpszBuffer);

    Arguments:  lpszSource - name of input file
                lpszBuffer - pointer to a buffer that will be filled in with
                             the expanded name of the compressed source file

    Returns:    int - TRUE if successful.  One of the LZERROR_ codes if
                      unsuccessful.

    Looks in the header of a compressed file to find its original expanded
    name.  For uncompressed files, lpszBuffer will hold a copy of lpszSource.



DOS:
int FAR PASCAL LZOpenFile(LPSTR lpFileName, WORD wStyle)

Windows:
int FAR PASCAL LZOpenFile(LPSTR lpFileName, LPOFSTRUCT lpReOpenBuf,
                          WORD wStyle);

    Arguments:  lpFileName  - name of input file
                lpReOpenBuf - pointer to LPOFSTRUCT to be used by OpenFile()
                wStyle      - OpenFile() action to take

    Returns:    int - LZFile struct table offset or DOS file handle if
                      successful.  One of the LZERROR_ codes if unsuccessful.

    This function takes arguments similar to those of OpenFile().  It opens
    a file, using the Windows OpenFile() function.  If the file is opened
    in any mode other than read-only, OpenFile()'s result is returned (a
    DOS file handle if successful).  If the file has been opened read-only
    and the file is compressed, LZInit() is called to create an LZFile
    buffer structure, and LZOpenFile() returns the table offset (plus bias)
    of the struct's global handle instead of a DOS file handle.



int FAR PASCAL LZInit(int doshSource);

    Arguments:  doshSource - source DOS file handle

    Returns:    int - LZFile struct table offset or DOS file handle if
                      successful.  One of the LZERROR_ codes if unsuccessful.

    This function takes a DOS file handle as its argument.  The file should
    first be opened read-only (with Windows OpenFile()).  If the file is
    compressed, the table offset (plus bias) of the global handle to the
    structure used by the following functions is returned.  Storage for the
    structure is allocated from the global heap.  If the file is not
    compressed, the DOS file handle is returned.

    The structure contains information about the compressed file and its
    expanded image, and buffers used in I/O and expansion.



LONG FAR PASCAL LZSeek(int oLZFile, long lSeekTo, int nMode);

    Arguments:  oLZFile - source LZFile struct identifier or DOS file handle
                lSeekTo - number of bytes past nMode target to seek
                nMode   - seek mode as in _llseek()

    Returns:    LONG - Offset of the seek target if successful.  One of the
                LZERROR_ codes if unsuccessful.

    Works like _llseek().

    Information in the LZfile structure is used to determine whether or not
    the file is compressed.  If the file is not compressed, _llseek() is
    called, using the DOS file handle.

    If the file is compressed, _llseek() is emulated on the expanded
    (buffered) image of the file.  Enough of the file is read and
    decompressed so that the desired data (seek destination) is in the
    output buffer in the LZfile structure.



int FAR PASCAL LZRead(int oLZFile, LPSTR lpBuf, int nCount);

    Arguments:  oLZFile - source LZFile struct identifier or DOS file handle
                lpBuf   - pointer to destination buffer for bytes read
                nCount  - number of bytes to read

    Returns:    int - Number of bytes copied to destination buffer if
                      successful.  One of the LZERROR_ codes if unsuccessful.

    Works like _lread().

    If the file is not compressed, _lread() is called, using the DOS file
    handle.

    If the file is compressed, the file is read, decompressed, and copied
    from the buffer in the LZfile structure to lpBuf until either EOF is
    reached or nCount bytes have been written to the output buffer.

    The actual number of bytes written is returned.  It is less than nCount
    only if EOF has been reached.



VOID FAR PASCAL LZClose(int oLZFile);

    Arguments:  oLZFile - source LZFile struct identifier or DOS file handle

    Returns:    VOID

    The file is closed.  If the file is compressed, the global heap space
    occupied by the associated LZfile structure is freed.



int FAR PASCAL LZStart(void);

    Arguments:  void

    Returns:    int - TRUE if function is successful, LZERROR_GLOBALLOC if
                      not.

    Allocates buffers for CopyLZFile().


LONG FAR PASCAL CopyLZFile(int doshSource, int doshDest);

    Arguments:  doshSource  - source DOS file handle
                doshDest    - destination DOS file handle

    Returns:    LONG - Number of bytes written to destination handle if copy
                       was successful.  One of the LZERROR_ codes if
                       unsuccessful.

    Works like LZCopy(), but doesn't free the buffers used when it finishes.



VOID FAR PASCAL LZDone(void);

    Arguments:  void

    Returns:    VOID

    Frees buffers allocated by LZStart().



LZERROR_ return codes:

    LZERROR_BADINHANDLE  - Invalid input handle.
    LZERROR_BADOUTHANDLE - Invalid output handle.
    LZERROR_READ         - Bad compressed file format.
    LZERROR_WRITE        - Out of space for output file.
    LZERROR_GLOBALLOC    - Insufficient memory for buffers.
    LZERROR_GLOBLOCK     - Bad global handle.
    LZERROR_BADVALUE     - Input parameter out of acceptable range.
    LZERROR_UNKNOWNALG   - Compression algorithm not recognized.

    The LZERROR_ return codes are all negative.

