1626 lines
53 KiB
HTML
1626 lines
53 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<!-- This HTML file has been created by texi2html 1.51
|
|
from manual.texi on 23 August 1998 -->
|
|
|
|
<TITLE>bzip2 and libbzip2 - Programming with libbzip2</TITLE>
|
|
</HEAD>
|
|
<BODY>
|
|
Go to the <A HREF="manual_1.html">first</A>, <A HREF="manual_2.html">previous</A>, <A HREF="manual_4.html">next</A>, <A HREF="manual_4.html">last</A> section, <A HREF="manual_toc.html">table of contents</A>.
|
|
<P><HR><P>
|
|
|
|
|
|
<H1><A NAME="SEC3" HREF="manual_toc.html#TOC3">Programming with <CODE>libbzip2</CODE></A></H1>
|
|
|
|
<P>
|
|
This chapter describes the programming interface to <CODE>libbzip2</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
For general background information, particularly about memory
|
|
use and performance aspects, you'd be well advised to read Chapter 2
|
|
as well.
|
|
|
|
</P>
|
|
|
|
|
|
<H2><A NAME="SEC4" HREF="manual_toc.html#TOC4">Top-level structure</A></H2>
|
|
|
|
<P>
|
|
<CODE>libbzip2</CODE> is a flexible library for compressing and decompressing
|
|
data in the <CODE>bzip2</CODE> data format. Although packaged as a single
|
|
entity, it helps to regard the library as three separate parts: the low
|
|
level interface, and the high level interface, and some utility
|
|
functions.
|
|
|
|
</P>
|
|
<P>
|
|
The structure of <CODE>libbzip2</CODE>'s interfaces is similar to
|
|
that of Jean-loup Gailly's and Mark Adler's excellent <CODE>zlib</CODE>
|
|
library.
|
|
|
|
</P>
|
|
|
|
|
|
<H3><A NAME="SEC5" HREF="manual_toc.html#TOC5">Low-level summary</A></H3>
|
|
|
|
<P>
|
|
This interface provides services for compressing and decompressing
|
|
data in memory. There's no provision for dealing with files, streams
|
|
or any other I/O mechanisms, just straight memory-to-memory work.
|
|
In fact, this part of the library can be compiled without inclusion
|
|
of <CODE>stdio.h</CODE>, which may be helpful for embedded applications.
|
|
|
|
</P>
|
|
<P>
|
|
The low-level part of the library has no global variables and
|
|
is therefore thread-safe.
|
|
|
|
</P>
|
|
<P>
|
|
Six routines make up the low level interface:
|
|
<CODE>bzCompressInit</CODE>, <CODE>bzCompress</CODE>, and <BR> <CODE>bzCompressEnd</CODE>
|
|
for compression,
|
|
and a corresponding trio <CODE>bzDecompressInit</CODE>, <BR> <CODE>bzDecompress</CODE>
|
|
and <CODE>bzDecompressEnd</CODE> for decompression.
|
|
The <CODE>*Init</CODE> functions allocate
|
|
memory for compression/decompression and do other
|
|
initialisations, whilst the <CODE>*End</CODE> functions close down operations
|
|
and release memory.
|
|
|
|
</P>
|
|
<P>
|
|
The real work is done by <CODE>bzCompress</CODE> and <CODE>bzDecompress</CODE>.
|
|
These compress/decompress data from a user-supplied input buffer
|
|
to a user-supplied output buffer. These buffers can be any size;
|
|
arbitrary quantities of data are handled by making repeated calls
|
|
to these functions. This is a flexible mechanism allowing a
|
|
consumer-pull style of activity, or producer-push, or a mixture of
|
|
both.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC6" HREF="manual_toc.html#TOC6">High-level summary</A></H3>
|
|
|
|
<P>
|
|
This interface provides some handy wrappers around the low-level
|
|
interface to facilitate reading and writing <CODE>bzip2</CODE> format
|
|
files (<CODE>.bz2</CODE> files). The routines provide hooks to facilitate
|
|
reading files in which the <CODE>bzip2</CODE> data stream is embedded
|
|
within some larger-scale file structure, or where there are
|
|
multiple <CODE>bzip2</CODE> data streams concatenated end-to-end.
|
|
|
|
</P>
|
|
<P>
|
|
For reading files, <CODE>bzReadOpen</CODE>, <CODE>bzRead</CODE>, <CODE>bzReadClose</CODE>
|
|
and <CODE>bzReadGetUnused</CODE> are supplied. For writing files,
|
|
<CODE>bzWriteOpen</CODE>, <CODE>bzWrite</CODE> and <CODE>bzWriteFinish</CODE> are
|
|
available.
|
|
|
|
</P>
|
|
<P>
|
|
As with the low-level library, no global variables are used
|
|
so the library is per se thread-safe. However, if I/O errors
|
|
occur whilst reading or writing the underlying compressed files,
|
|
you may have to consult <CODE>errno</CODE> to determine the cause of
|
|
the error. In that case, you'd need a C library which correctly
|
|
supports <CODE>errno</CODE> in a multithreaded environment.
|
|
|
|
</P>
|
|
<P>
|
|
To make the library a little simpler and more portable,
|
|
<CODE>bzReadOpen</CODE> and <CODE>bzWriteOpen</CODE> require you to pass them file
|
|
handles (<CODE>FILE*</CODE>s) which have previously been opened for reading or
|
|
writing respectively. That avoids portability problems associated with
|
|
file operations and file attributes, whilst not being much of an
|
|
imposition on the programmer.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC7" HREF="manual_toc.html#TOC7">Utility functions summary</A></H3>
|
|
<P>
|
|
For very simple needs, <CODE>bzBuffToBuffCompress</CODE> and
|
|
<CODE>bzBuffToBuffDecompress</CODE> are provided. These compress
|
|
data in memory from one buffer to another buffer in a single
|
|
function call. You should assess whether these functions
|
|
fulfill your memory-to-memory compression/decompression
|
|
requirements before investing effort in understanding the more
|
|
general but more complex low-level interface.
|
|
|
|
</P>
|
|
<P>
|
|
Yoshioka Tsuneo (<CODE>QWF00133@niftyserve.or.jp</CODE> /
|
|
<CODE>tsuneo-y@is.aist-nara.ac.jp</CODE>) has contributed some functions to
|
|
give better <CODE>zlib</CODE> compatibility. These functions are
|
|
<CODE>bzopen</CODE>, <CODE>bzread</CODE>, <CODE>bzwrite</CODE>, <CODE>bzflush</CODE>,
|
|
<CODE>bzclose</CODE>,
|
|
<CODE>bzerror</CODE> and <CODE>bzlibVersion</CODE>. You may find these functions
|
|
more convenient for simple file reading and writing, than those in the
|
|
high-level interface. These functions are not (yet) officially part of
|
|
the library, and are not further documented here. If they break, you
|
|
get to keep all the pieces. I hope to document them properly when time
|
|
permits.
|
|
|
|
</P>
|
|
<P>
|
|
Yoshioka also contributed modifications to allow the library to be
|
|
built as a Windows DLL.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC8" HREF="manual_toc.html#TOC8">Error handling</A></H2>
|
|
|
|
<P>
|
|
The library is designed to recover cleanly in all situations, including
|
|
the worst-case situation of decompressing random data. I'm not
|
|
100% sure that it can always do this, so you might want to add
|
|
a signal handler to catch segmentation violations during decompression
|
|
if you are feeling especially paranoid. I would be interested in
|
|
hearing more about the robustness of the library to corrupted
|
|
compressed data.
|
|
|
|
</P>
|
|
<P>
|
|
The file <CODE>bzlib.h</CODE> contains all definitions needed to use
|
|
the library. In particular, you should definitely not include
|
|
<CODE>bzlib_private.h</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
In <CODE>bzlib.h</CODE>, the various return values are defined. The following
|
|
list is not intended as an exhaustive description of the circumstances
|
|
in which a given value may be returned -- those descriptions are given
|
|
later. Rather, it is intended to convey the rough meaning of each
|
|
return value. The first five actions are normal and not intended to
|
|
denote an error situation.
|
|
<DL COMPACT>
|
|
|
|
<DT><CODE>BZ_OK</CODE>
|
|
<DD>
|
|
The requested action was completed successfully.
|
|
<DT><CODE>BZ_RUN_OK</CODE>
|
|
<DD>
|
|
<DT><CODE>BZ_FLUSH_OK</CODE>
|
|
<DD>
|
|
<DT><CODE>BZ_FINISH_OK</CODE>
|
|
<DD>
|
|
In <CODE>bzCompress</CODE>, the requested flush/finish/nothing-special action
|
|
was completed successfully.
|
|
<DT><CODE>BZ_STREAM_END</CODE>
|
|
<DD>
|
|
Compression of data was completed, or the logical stream end was
|
|
detected during decompression.
|
|
</DL>
|
|
|
|
<P>
|
|
The following return values indicate an error of some kind.
|
|
<DL COMPACT>
|
|
|
|
<DT><CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
<DD>
|
|
When using the library, it is important to call the functions in the
|
|
correct sequence and with data structures (buffers etc) in the correct
|
|
states. <CODE>libbzip2</CODE> checks as much as it can to ensure this is
|
|
happening, and returns <CODE>BZ_SEQUENCE_ERROR</CODE> if not. Code which
|
|
complies precisely with the function semantics, as detailed below,
|
|
should never receive this value; such an event denotes buggy code
|
|
which you should investigate.
|
|
<DT><CODE>BZ_PARAM_ERROR</CODE>
|
|
<DD>
|
|
Returned when a parameter to a function call is out of range
|
|
or otherwise manifestly incorrect. As with <CODE>BZ_SEQUENCE_ERROR</CODE>,
|
|
this denotes a bug in the client code. The distinction between
|
|
<CODE>BZ_PARAM_ERROR</CODE> and <CODE>BZ_SEQUENCE_ERROR</CODE> is a bit hazy, but still worth
|
|
making.
|
|
<DT><CODE>BZ_MEM_ERROR</CODE>
|
|
<DD>
|
|
Returned when a request to allocate memory failed. Note that the
|
|
quantity of memory needed to decompress a stream cannot be determined
|
|
until the stream's header has been read. So <CODE>bzDecompress</CODE> and
|
|
<CODE>bzRead</CODE> may return <CODE>BZ_MEM_ERROR</CODE> even though some of
|
|
the compressed data has been read. The same is not true for
|
|
compression; once <CODE>bzCompressInit</CODE> or <CODE>bzWriteOpen</CODE> have
|
|
successfully completed, <CODE>BZ_MEM_ERROR</CODE> cannot occur.
|
|
<DT><CODE>BZ_DATA_ERROR</CODE>
|
|
<DD>
|
|
Returned when a data integrity error is detected during decompression.
|
|
Most importantly, this means when stored and computed CRCs for the
|
|
data do not match. This value is also returned upon detection of any
|
|
other anomaly in the compressed data.
|
|
<DT><CODE>BZ_DATA_ERROR_MAGIC</CODE>
|
|
<DD>
|
|
As a special case of <CODE>BZ_DATA_ERROR</CODE>, it is sometimes useful to
|
|
know when the compressed stream does not start with the correct
|
|
magic bytes (<CODE>'B' 'Z' 'h'</CODE>).
|
|
<DT><CODE>BZ_IO_ERROR</CODE>
|
|
<DD>
|
|
Returned by <CODE>bzRead</CODE> and <CODE>bzRead</CODE> when there is an error
|
|
reading or writing in the compressed file, and by <CODE>bzReadOpen</CODE>
|
|
and <CODE>bzWriteOpen</CODE> for attempts to use a file for which the
|
|
error indicator (viz, <CODE>ferror(f)</CODE>) is set.
|
|
On receipt of <CODE>BZ_IO_ERROR</CODE>, the caller should consult
|
|
<CODE>errno</CODE> and/or <CODE>perror</CODE> to acquire operating-system
|
|
specific information about the problem.
|
|
<DT><CODE>BZ_UNEXPECTED_EOF</CODE>
|
|
<DD>
|
|
Returned by <CODE>bzRead</CODE> when the compressed file finishes
|
|
before the logical end of stream is detected.
|
|
<DT><CODE>BZ_OUTBUFF_FULL</CODE>
|
|
<DD>
|
|
Returned by <CODE>bzBuffToBuffCompress</CODE> and
|
|
<CODE>bzBuffToBuffDecompress</CODE> to indicate that the output data
|
|
will not fit into the output buffer provided.
|
|
</DL>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC9" HREF="manual_toc.html#TOC9">Low-level interface</A></H2>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC10" HREF="manual_toc.html#TOC10"><CODE>bzCompressInit</CODE></A></H3>
|
|
|
|
<PRE>
|
|
typedef
|
|
struct {
|
|
char *next_in;
|
|
unsigned int avail_in;
|
|
unsigned int total_in;
|
|
|
|
char *next_out;
|
|
unsigned int avail_out;
|
|
unsigned int total_out;
|
|
|
|
void *state;
|
|
|
|
void *(*bzalloc)(void *,int,int);
|
|
void (*bzfree)(void *,void *);
|
|
void *opaque;
|
|
}
|
|
bz_stream;
|
|
|
|
int bzCompressInit ( bz_stream *strm,
|
|
int blockSize100k,
|
|
int verbosity,
|
|
int workFactor );
|
|
|
|
</PRE>
|
|
|
|
<P>
|
|
Prepares for compression. The <CODE>bz_stream</CODE> structure
|
|
holds all data pertaining to the compression activity.
|
|
A <CODE>bz_stream</CODE> structure should be allocated and initialised
|
|
prior to the call.
|
|
The fields of <CODE>bz_stream</CODE>
|
|
comprise the entirety of the user-visible data. <CODE>state</CODE>
|
|
is a pointer to the private data structures required for compression.
|
|
|
|
</P>
|
|
<P>
|
|
Custom memory allocators are supported, via fields <CODE>bzalloc</CODE>,
|
|
<CODE>bzfree</CODE>,
|
|
and <CODE>opaque</CODE>. The value
|
|
<CODE>opaque</CODE> is passed to as the first argument to
|
|
all calls to <CODE>bzalloc</CODE> and <CODE>bzfree</CODE>, but is
|
|
otherwise ignored by the library.
|
|
The call <CODE>bzalloc ( opaque, n, m )</CODE> is expected to return a
|
|
pointer <CODE>p</CODE> to
|
|
<CODE>n * m</CODE> bytes of memory, and <CODE>bzfree ( opaque, p )</CODE>
|
|
should free
|
|
that memory.
|
|
|
|
</P>
|
|
<P>
|
|
If you don't want to use a custom memory allocator, set <CODE>bzalloc</CODE>,
|
|
<CODE>bzfree</CODE> and
|
|
<CODE>opaque</CODE> to <CODE>NULL</CODE>,
|
|
and the library will then use the standard <CODE>malloc</CODE>/<CODE>free</CODE>
|
|
routines.
|
|
|
|
</P>
|
|
<P>
|
|
Before calling <CODE>bzCompressInit</CODE>, fields <CODE>bzalloc</CODE>,
|
|
<CODE>bzfree</CODE> and <CODE>opaque</CODE> should
|
|
be filled appropriately, as just described. Upon return, the internal
|
|
state will have been allocated and initialised, and <CODE>total_in</CODE> and
|
|
<CODE>total_out</CODE> will have been set to zero.
|
|
These last two fields are used by the library
|
|
to inform the caller of the total amount of data passed into and out of
|
|
the library, respectively. You should not try to change them.
|
|
|
|
</P>
|
|
<P>
|
|
Parameter <CODE>blockSize100k</CODE> specifies the block size to be used for
|
|
compression. It should be a value between 1 and 9 inclusive, and the
|
|
actual block size used is 100000 x this figure. 9 gives the best
|
|
compression but takes most memory.
|
|
|
|
</P>
|
|
<P>
|
|
Parameter <CODE>verbosity</CODE> should be set to a number between 0 and 4
|
|
inclusive. 0 is silent, and greater numbers give increasingly verbose
|
|
monitoring/debugging output. If the library has been compiled with
|
|
<CODE>-DBZ_NO_STDIO</CODE>, no such output will appear for any verbosity
|
|
setting.
|
|
|
|
</P>
|
|
<P>
|
|
Parameter <CODE>workFactor</CODE> controls how the compression phase behaves
|
|
when presented with worst case, highly repetitive, input data.
|
|
If compression runs into difficulties caused by repetitive data,
|
|
some pseudo-random variations are inserted into the block, and
|
|
compression is restarted. Lower values of <CODE>workFactor</CODE>
|
|
reduce the tolerance of compression to repetitive data.
|
|
You should set this parameter carefully; too low, and
|
|
compression ratio suffers, too high, and your average-to-worst
|
|
case compression times can become very large.
|
|
The default value of 30
|
|
gives reasonable behaviour over a wide range of circumstances.
|
|
|
|
</P>
|
|
<P>
|
|
Allowable values range from 0 to 250 inclusive. 0 is a special
|
|
case, equivalent to using the default value of 30.
|
|
|
|
</P>
|
|
<P>
|
|
Note that the randomisation process is entirely transparent.
|
|
If the library decides to randomise and restart compression on a
|
|
block, it does so without comment. Randomised blocks are
|
|
automatically de-randomised during decompression, so data
|
|
integrity is never compromised.
|
|
|
|
</P>
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>strm</CODE> is <CODE>NULL</CODE>
|
|
or <CODE>blockSize</CODE> < 1 or <CODE>blockSize</CODE> > 9
|
|
or <CODE>verbosity</CODE> < 0 or <CODE>verbosity</CODE> > 4
|
|
or <CODE>workFactor</CODE> < 0 or <CODE>workFactor</CODE> > 250
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if not enough memory is available
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
<CODE>bzCompress</CODE>
|
|
if <CODE>BZ_OK</CODE> is returned
|
|
no specific action needed in case of error
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC11" HREF="manual_toc.html#TOC11"><CODE>bzCompress</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzCompress ( bz_stream *strm, int action );
|
|
</PRE>
|
|
|
|
<P>
|
|
Provides more input and/or output buffer space for the library. The
|
|
caller maintains input and output buffers, and calls <CODE>bzCompress</CODE> to
|
|
transfer data between them.
|
|
|
|
</P>
|
|
<P>
|
|
Before each call to <CODE>bzCompress</CODE>, <CODE>next_in</CODE> should point at
|
|
the data to be compressed, and <CODE>avail_in</CODE> should indicate how many
|
|
bytes the library may read. <CODE>bzCompress</CODE> updates <CODE>next_in</CODE>,
|
|
<CODE>avail_in</CODE> and <CODE>total_in</CODE> to reflect the number of bytes it
|
|
has read.
|
|
|
|
</P>
|
|
<P>
|
|
Similarly, <CODE>next_out</CODE> should point to a buffer in which the
|
|
compressed data is to be placed, with <CODE>avail_out</CODE> indicating how
|
|
much output space is available. <CODE>bzCompress</CODE> updates
|
|
<CODE>next_out</CODE>, <CODE>avail_out</CODE> and <CODE>total_out</CODE> to reflect the
|
|
number of bytes output.
|
|
|
|
</P>
|
|
<P>
|
|
You may provide and remove as little or as much data as you like on each
|
|
call of <CODE>bzCompress</CODE>. In the limit, it is acceptable to supply and
|
|
remove data one byte at a time, although this would be terribly
|
|
inefficient. You should always ensure that at least one byte of output
|
|
space is available at each call.
|
|
|
|
</P>
|
|
<P>
|
|
A second purpose of <CODE>bzCompress</CODE> is to request a change of mode of the
|
|
compressed stream.
|
|
|
|
</P>
|
|
<P>
|
|
Conceptually, a compressed stream can be in one of four states: IDLE,
|
|
RUNNING, FLUSHING and FINISHING. Before initialisation
|
|
(<CODE>bzCompressInit</CODE>) and after termination (<CODE>bzCompressEnd</CODE>), a
|
|
stream is regarded as IDLE.
|
|
|
|
</P>
|
|
<P>
|
|
Upon initialisation (<CODE>bzCompressInit</CODE>), the stream is placed in the
|
|
RUNNING state. Subsequent calls to <CODE>bzCompress</CODE> should pass
|
|
<CODE>BZ_RUN</CODE> as the requested action; other actions are illegal and
|
|
will result in <CODE>BZ_SEQUENCE_ERROR</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
At some point, the calling program will have provided all the input data
|
|
it wants to. It will then want to finish up -- in effect, asking the
|
|
library to process any data it might have buffered internally. In this
|
|
state, <CODE>bzCompress</CODE> will no longer attempt to read data from
|
|
<CODE>next_in</CODE>, but it will want to write data to <CODE>next_out</CODE>.
|
|
Because the output buffer supplied by the user can be arbitrarily small,
|
|
the finishing-up operation cannot necessarily be done with a single call
|
|
of <CODE>bzCompress</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Instead, the calling program passes <CODE>BZ_FINISH</CODE> as an action to
|
|
<CODE>bzCompress</CODE>. This changes the stream's state to FINISHING. Any
|
|
remaining input (ie, <CODE>next_in[0 .. avail_in-1]</CODE>) is compressed and
|
|
transferred to the output buffer. To do this, <CODE>bzCompress</CODE> must be
|
|
called repeatedly until all the output has been consumed. At that
|
|
point, <CODE>bzCompress</CODE> returns <CODE>BZ_STREAM_END</CODE>, and the stream's
|
|
state is set back to IDLE. <CODE>bzCompressEnd</CODE> should then be
|
|
called.
|
|
|
|
</P>
|
|
<P>
|
|
Just to make sure the calling program does not cheat, the library makes
|
|
a note of <CODE>avail_in</CODE> at the time of the first call to
|
|
<CODE>bzCompress</CODE> which has <CODE>BZ_FINISH</CODE> as an action (ie, at the
|
|
time the program has announced its intention to not supply any more
|
|
input). By comparing this value with that of <CODE>avail_in</CODE> over
|
|
subsequent calls to <CODE>bzCompress</CODE>, the library can detect any
|
|
attempts to slip in more data to compress. Any calls for which this is
|
|
detected will return <CODE>BZ_SEQUENCE_ERROR</CODE>. This indicates a
|
|
programming mistake which should be corrected.
|
|
|
|
</P>
|
|
<P>
|
|
Instead of asking to finish, the calling program may ask
|
|
<CODE>bzCompress</CODE> to take all the remaining input, compress it and
|
|
terminate the current (Burrows-Wheeler) compression block. This could
|
|
be useful for error control purposes. The mechanism is analogous to
|
|
that for finishing: call <CODE>bzCompress</CODE> with an action of
|
|
<CODE>BZ_FLUSH</CODE>, remove output data, and persist with the
|
|
<CODE>BZ_FLUSH</CODE> action until the value <CODE>BZ_RUN</CODE> is returned. As
|
|
with finishing, <CODE>bzCompress</CODE> detects any attempt to provide more
|
|
input data once the flush has begun.
|
|
|
|
</P>
|
|
<P>
|
|
Once the flush is complete, the stream returns to the normal RUNNING
|
|
state.
|
|
|
|
</P>
|
|
<P>
|
|
This all sounds pretty complex, but isn't really. Here's a table
|
|
which shows which actions are allowable in each state, what action
|
|
will be taken, what the next state is, and what the non-error return
|
|
values are. Note that you can't explicitly ask what state the
|
|
stream is in, but nor do you need to -- it can be inferred from the
|
|
values returned by <CODE>bzCompress</CODE>.
|
|
|
|
<PRE>
|
|
IDLE/<CODE>any</CODE>
|
|
Illegal. IDLE state only exists after <CODE>bzCompressEnd</CODE> or
|
|
before <CODE>bzCompressInit</CODE>.
|
|
Return value = <CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
|
|
RUNNING/<CODE>BZ_RUN</CODE>
|
|
Compress from <CODE>next_in</CODE> to <CODE>next_out</CODE> as much as possible.
|
|
Next state = RUNNING
|
|
Return value = <CODE>BZ_RUN_OK</CODE>
|
|
|
|
RUNNING/<CODE>BZ_FLUSH</CODE>
|
|
Remember current value of <CODE>next_in</CODE>. Compress from <CODE>next_in</CODE>
|
|
to <CODE>next_out</CODE> as much as possible, but do not accept any more input.
|
|
Next state = FLUSHING
|
|
Return value = <CODE>BZ_FLUSH_OK</CODE>
|
|
|
|
RUNNING/<CODE>BZ_FINISH</CODE>
|
|
Remember current value of <CODE>next_in</CODE>. Compress from <CODE>next_in</CODE>
|
|
to <CODE>next_out</CODE> as much as possible, but do not accept any more input.
|
|
Next state = FINISHING
|
|
Return value = <CODE>BZ_FINISH_OK</CODE>
|
|
|
|
FLUSHING/<CODE>BZ_FLUSH</CODE>
|
|
Compress from <CODE>next_in</CODE> to <CODE>next_out</CODE> as much as possible,
|
|
but do not accept any more input.
|
|
If all the existing input has been used up
|
|
Next state = RUNNING; Return value = <CODE>BZ_RUN_OK</CODE>
|
|
else
|
|
Next state = FLUSHING; Return value = <CODE>BZ_FLUSH_OK</CODE>
|
|
|
|
FLUSHING/other
|
|
Illegal.
|
|
Return value = <CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
|
|
FINISHING/<CODE>BZ_FINISH</CODE>
|
|
Compress from <CODE>next_in</CODE> to <CODE>next_out</CODE> as much as possible,
|
|
but to not accept any more input.
|
|
If all the existing input has been used up and all compressed
|
|
output has been removed
|
|
Next state = IDLE; Return value = <CODE>BZ_STREAM_END</CODE>
|
|
else
|
|
Next state = FINISHING; Return value = <CODE>BZ_FINISHING</CODE>
|
|
|
|
FINISHING/other
|
|
Illegal.
|
|
Return value = <CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
</PRE>
|
|
|
|
<P>
|
|
That still looks complicated? Well, fair enough. The usual sequence
|
|
of calls for compressing a load of data is:
|
|
|
|
<UL>
|
|
<LI>Get started with <CODE>bzCompressInit</CODE>.
|
|
|
|
<LI>Shovel data in and shlurp out its compressed form using zero or more
|
|
|
|
calls of <CODE>bzCompress</CODE> with action = <CODE>BZ_RUN</CODE>.
|
|
<LI>Finish up.
|
|
|
|
Repeatedly call <CODE>bzCompress</CODE> with action = <CODE>BZ_FINISH</CODE>,
|
|
copying out the compressed output, until <CODE>BZ_STREAM_END</CODE> is returned.
|
|
<LI>Close up and go home. Call <CODE>bzCompressEnd</CODE>.
|
|
|
|
</UL>
|
|
|
|
<P>
|
|
If the data you want to compress fits into your input buffer all
|
|
at once, you can skip the calls of <CODE>bzCompress ( ..., BZ_RUN )</CODE> and
|
|
just do the <CODE>bzCompress ( ..., BZ_FINISH )</CODE> calls.
|
|
|
|
</P>
|
|
<P>
|
|
All required memory is allocated by <CODE>bzCompressInit</CODE>. The
|
|
compression library can accept any data at all (obviously). So you
|
|
shouldn't get any error return values from the <CODE>bzCompress</CODE> calls.
|
|
If you do, they will be <CODE>BZ_SEQUENCE_ERROR</CODE>, and indicate a bug in
|
|
your programming.
|
|
|
|
</P>
|
|
<P>
|
|
Trivial other possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>strm</CODE> is <CODE>NULL</CODE>, or <CODE>strm->s</CODE> is <CODE>NULL</CODE>
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC12" HREF="manual_toc.html#TOC12"><CODE>bzCompressEnd</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzCompressEnd ( bz_stream *strm );
|
|
</PRE>
|
|
|
|
<P>
|
|
Releases all memory associated with a compression stream.
|
|
|
|
</P>
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE> if <CODE>strm</CODE> is <CODE>NULL</CODE> or <CODE>strm->s</CODE> is <CODE>NULL</CODE>
|
|
<CODE>BZ_OK</CODE> otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC13" HREF="manual_toc.html#TOC13"><CODE>bzDecompressInit</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzDecompressInit ( bz_stream *strm, int verbosity, int small );
|
|
</PRE>
|
|
|
|
<P>
|
|
Prepares for decompression. As with <CODE>bzCompressInit</CODE>, a
|
|
<CODE>bz_stream</CODE> record should be allocated and initialised before the
|
|
call. Fields <CODE>bzalloc</CODE>, <CODE>bzfree</CODE> and <CODE>opaque</CODE> should be
|
|
set if a custom memory allocator is required, or made <CODE>NULL</CODE> for
|
|
the normal <CODE>malloc</CODE>/<CODE>free</CODE> routines. Upon return, the internal
|
|
state will have been initialised, and <CODE>total_in</CODE> and
|
|
<CODE>total_out</CODE> will be zero.
|
|
|
|
</P>
|
|
<P>
|
|
For the meaning of parameter <CODE>verbosity</CODE>, see <CODE>bzCompressInit</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
If <CODE>small</CODE> is nonzero, the library will use an alternative
|
|
decompression algorithm which uses less memory but at the cost of
|
|
decompressing more slowly (roughly speaking, half the speed, but the
|
|
maximum memory requirement drops to around 2300k). See Chapter 2 for
|
|
more information on memory management.
|
|
|
|
</P>
|
|
<P>
|
|
Note that the amount of memory needed to decompress
|
|
a stream cannot be determined until the stream's header has been read,
|
|
so even if <CODE>bzDecompressInit</CODE> succeeds, a subsequent
|
|
<CODE>bzDecompress</CODE> could fail with <CODE>BZ_MEM_ERROR</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>(small != 0 && small != 1)</CODE>
|
|
or <CODE>(verbosity < 0 || verbosity > 4)</CODE>
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if insufficient memory is available
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
<CODE>bzDecompress</CODE>
|
|
if <CODE>BZ_OK</CODE> was returned
|
|
no specific action required in case of error
|
|
</PRE>
|
|
|
|
<P>
|
|
|
|
|
|
</P>
|
|
|
|
|
|
<H3><A NAME="SEC14" HREF="manual_toc.html#TOC14"><CODE>bzDecompress</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzDecompress ( bz_stream *strm );
|
|
</PRE>
|
|
|
|
<P>
|
|
Provides more input and/out output buffer space for the library. The
|
|
caller maintains input and output buffers, and uses <CODE>bzDecompress</CODE>
|
|
to transfer data between them.
|
|
|
|
</P>
|
|
<P>
|
|
Before each call to <CODE>bzDecompress</CODE>, <CODE>next_in</CODE>
|
|
should point at the compressed data,
|
|
and <CODE>avail_in</CODE> should indicate how many bytes the library
|
|
may read. <CODE>bzDecompress</CODE> updates <CODE>next_in</CODE>, <CODE>avail_in</CODE>
|
|
and <CODE>total_in</CODE>
|
|
to reflect the number of bytes it has read.
|
|
|
|
</P>
|
|
<P>
|
|
Similarly, <CODE>next_out</CODE> should point to a buffer in which the uncompressed
|
|
output is to be placed, with <CODE>avail_out</CODE> indicating how much output space
|
|
is available. <CODE>bzCompress</CODE> updates <CODE>next_out</CODE>,
|
|
<CODE>avail_out</CODE> and <CODE>total_out</CODE> to reflect
|
|
the number of bytes output.
|
|
|
|
</P>
|
|
<P>
|
|
You may provide and remove as little or as much data as you like on
|
|
each call of <CODE>bzDecompress</CODE>.
|
|
In the limit, it is acceptable to
|
|
supply and remove data one byte at a time, although this would be
|
|
terribly inefficient. You should always ensure that at least one
|
|
byte of output space is available at each call.
|
|
|
|
</P>
|
|
<P>
|
|
Use of <CODE>bzDecompress</CODE> is simpler than <CODE>bzCompress</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
You should provide input and remove output as described above, and
|
|
repeatedly call <CODE>bzDecompress</CODE> until <CODE>BZ_STREAM_END</CODE> is
|
|
returned. Appearance of <CODE>BZ_STREAM_END</CODE> denotes that
|
|
<CODE>bzDecompress</CODE> has detected the logical end of the compressed
|
|
stream. <CODE>bzDecompress</CODE> will not produce <CODE>BZ_STREAM_END</CODE> until
|
|
all output data has been placed into the output buffer, so once
|
|
<CODE>BZ_STREAM_END</CODE> appears, you are guaranteed to have available all
|
|
the decompressed output, and <CODE>bzDecompressEnd</CODE> can safely be
|
|
called.
|
|
|
|
</P>
|
|
<P>
|
|
If case of an error return value, you should call <CODE>bzDecompressEnd</CODE>
|
|
to clean up and release memory.
|
|
|
|
</P>
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>strm</CODE> is <CODE>NULL</CODE> or <CODE>strm->s</CODE> is <CODE>NULL</CODE>
|
|
or <CODE>strm->avail_out < 1</CODE>
|
|
<CODE>BZ_DATA_ERROR</CODE>
|
|
if a data integrity error is detected in the compressed stream
|
|
<CODE>BZ_DATA_ERROR_MAGIC</CODE>
|
|
if the compressed stream doesn't begin with the right magic bytes
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if there wasn't enough memory available
|
|
<CODE>BZ_STREAM_END</CODE>
|
|
if the logical end of the data stream was detected and all
|
|
output in has been consumed, eg <CODE>s->avail_out > 0</CODE>
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
<CODE>bzDecompress</CODE>
|
|
if <CODE>BZ_OK</CODE> was returned
|
|
<CODE>bzDecompressEnd</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC15" HREF="manual_toc.html#TOC15"><CODE>bzDecompressEnd</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzDecompressEnd ( bz_stream *strm );
|
|
</PRE>
|
|
|
|
<P>
|
|
Releases all memory associated with a decompression stream.
|
|
|
|
</P>
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>strm</CODE> is <CODE>NULL</CODE> or <CODE>strm->s</CODE> is <CODE>NULL</CODE>
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
None.
|
|
</PRE>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC16" HREF="manual_toc.html#TOC16">High-level interface</A></H2>
|
|
|
|
<P>
|
|
This interface provides functions for reading and writing
|
|
<CODE>bzip2</CODE> format files. First, some general points.
|
|
|
|
</P>
|
|
|
|
<UL>
|
|
<LI>All of the functions take an <CODE>int*</CODE> first argument,
|
|
|
|
<CODE>bzerror</CODE>.
|
|
After each call, <CODE>bzerror</CODE> should be consulted first to determine
|
|
the outcome of the call. If <CODE>bzerror</CODE> is <CODE>BZ_OK</CODE>,
|
|
the call completed
|
|
successfully, and only then should the return value of the function
|
|
(if any) be consulted. If <CODE>bzerror</CODE> is <CODE>BZ_IO_ERROR</CODE>,
|
|
there was an error
|
|
reading/writing the underlying compressed file, and you should
|
|
then consult <CODE>errno</CODE>/<CODE>perror</CODE> to determine the
|
|
cause of the difficulty.
|
|
<CODE>bzerror</CODE> may also be set to various other values; precise details are
|
|
given on a per-function basis below.
|
|
<LI>If <CODE>bzerror</CODE> indicates an error
|
|
|
|
(ie, anything except <CODE>BZ_OK</CODE> and <CODE>BZ_STREAM_END</CODE>),
|
|
you should immediately call <CODE>bzReadClose</CODE> (or <CODE>bzWriteClose</CODE>,
|
|
depending on whether you are attempting to read or to write)
|
|
to free up all resources associated
|
|
with the stream. Once an error has been indicated, behaviour of all calls
|
|
except <CODE>bzReadClose</CODE> (<CODE>bzWriteClose</CODE>) is undefined.
|
|
The implication is that (1) <CODE>bzerror</CODE> should
|
|
be checked after each call, and (2) if <CODE>bzerror</CODE> indicates an error,
|
|
<CODE>bzReadClose</CODE> (<CODE>bzWriteClose</CODE>) should then be called to clean up.
|
|
<LI>The <CODE>FILE*</CODE> arguments passed to
|
|
|
|
<CODE>bzReadOpen</CODE>/<CODE>bzWriteOpen</CODE>
|
|
should be set to binary mode.
|
|
Most Unix systems will do this by default, but other platforms,
|
|
including Windows and Mac, will not. If you omit this, you may
|
|
encounter problems when moving code to new platforms.
|
|
<LI>Memory allocation requests are handled by
|
|
|
|
<CODE>malloc</CODE>/<CODE>free</CODE>.
|
|
At present
|
|
there is no facility for user-defined memory allocators in the file I/O
|
|
functions (could easily be added, though).
|
|
</UL>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC17" HREF="manual_toc.html#TOC17"><CODE>bzReadOpen</CODE></A></H3>
|
|
|
|
<PRE>
|
|
typedef void BZFILE;
|
|
|
|
BZFILE *bzReadOpen ( int *bzerror, FILE *f,
|
|
int small, int verbosity,
|
|
void *unused, int nUnused );
|
|
</PRE>
|
|
|
|
<P>
|
|
Prepare to read compressed data from file handle <CODE>f</CODE>. <CODE>f</CODE>
|
|
should refer to a file which has been opened for reading, and for which
|
|
the error indicator (<CODE>ferror(f)</CODE>)is not set. If <CODE>small</CODE> is 1,
|
|
the library will try to decompress using less memory, at the expense of
|
|
speed.
|
|
|
|
</P>
|
|
<P>
|
|
For reasons explained below, <CODE>bzRead</CODE> will decompress the
|
|
<CODE>nUnused</CODE> bytes starting at <CODE>unused</CODE>, before starting to read
|
|
from the file <CODE>f</CODE>. At most <CODE>BZ_MAX_UNUSED</CODE> bytes may be
|
|
supplied like this. If this facility is not required, you should pass
|
|
<CODE>NULL</CODE> and <CODE>0</CODE> for <CODE>unused</CODE> and n<CODE>Unused</CODE>
|
|
respectively.
|
|
|
|
</P>
|
|
<P>
|
|
For the meaning of parameters <CODE>small</CODE> and <CODE>verbosity</CODE>,
|
|
see <CODE>bzDecompressInit</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
The amount of memory needed to decompress a file cannot be determined
|
|
until the file's header has been read. So it is possible that
|
|
<CODE>bzReadOpen</CODE> returns <CODE>BZ_OK</CODE> but a subsequent call of
|
|
<CODE>bzRead</CODE> will return <CODE>BZ_MEM_ERROR</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Possible assignments to <CODE>bzerror</CODE>:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>f</CODE> is <CODE>NULL</CODE>
|
|
or <CODE>small</CODE> is neither <CODE>0</CODE> nor <CODE>1</CODE>
|
|
or <CODE>(unused == NULL && nUnused != 0)</CODE>
|
|
or <CODE>(unused != NULL && !(0 <= nUnused <= BZ_MAX_UNUSED))</CODE>
|
|
<CODE>BZ_IO_ERROR</CODE>
|
|
if <CODE>ferror(f)</CODE> is nonzero
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if insufficient memory is available
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise.
|
|
</PRE>
|
|
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
Pointer to an abstract <CODE>BZFILE</CODE>
|
|
if <CODE>bzerror</CODE> is <CODE>BZ_OK</CODE>
|
|
<CODE>NULL</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
<CODE>bzRead</CODE>
|
|
if <CODE>bzerror</CODE> is <CODE>BZ_OK</CODE>
|
|
<CODE>bzClose</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC18" HREF="manual_toc.html#TOC18"><CODE>bzRead</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzRead ( int *bzerror, BZFILE *b, void *buf, int len );
|
|
</PRE>
|
|
|
|
<P>
|
|
Reads up to <CODE>len</CODE> (uncompressed) bytes from the compressed file
|
|
<CODE>b</CODE> into
|
|
the buffer <CODE>buf</CODE>. If the read was successful,
|
|
<CODE>bzerror</CODE> is set to <CODE>BZ_OK</CODE>
|
|
and the number of bytes read is returned. If the logical end-of-stream
|
|
was detected, <CODE>bzerror</CODE> will be set to <CODE>BZ_STREAM_END</CODE>,
|
|
and the number
|
|
of bytes read is returned. All other <CODE>bzerror</CODE> values denote an error.
|
|
|
|
</P>
|
|
<P>
|
|
<CODE>bzRead</CODE> will supply <CODE>len</CODE> bytes,
|
|
unless the logical stream end is detected
|
|
or an error occurs. Because of this, it is possible to detect the
|
|
stream end by observing when the number of bytes returned is
|
|
less than the number
|
|
requested. Nevertheless, this is regarded as inadvisable; you should
|
|
instead check <CODE>bzerror</CODE> after every call and watch out for
|
|
<CODE>BZ_STREAM_END</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Internally, <CODE>bzRead</CODE> copies data from the compressed file in chunks
|
|
of size <CODE>BZ_MAX_UNUSED</CODE> bytes
|
|
before decompressing it. If the file contains more bytes than strictly
|
|
needed to reach the logical end-of-stream, <CODE>bzRead</CODE> will almost certainly
|
|
read some of the trailing data before signalling <CODE>BZ_SEQUENCE_END</CODE>.
|
|
To collect the read but unused data once <CODE>BZ_SEQUENCE_END</CODE> has
|
|
appeared, call <CODE>bzReadGetUnused</CODE> immediately before <CODE>bzReadClose</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Possible assignments to <CODE>bzerror</CODE>:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>b</CODE> is <CODE>NULL</CODE> or <CODE>buf</CODE> is <CODE>NULL</CODE> or <CODE>len < 0</CODE>
|
|
<CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
if <CODE>b</CODE> was opened with <CODE>bzWriteOpen</CODE>
|
|
<CODE>BZ_IO_ERROR</CODE>
|
|
if there is an error reading from the compressed file
|
|
<CODE>BZ_UNEXPECTED_EOF</CODE>
|
|
if the compressed file ended before the logical end-of-stream was detected
|
|
<CODE>BZ_DATA_ERROR</CODE>
|
|
if a data integrity error was detected in the compressed stream
|
|
<CODE>BZ_DATA_ERROR_MAGIC</CODE>
|
|
if the stream does not begin with the requisite header bytes (ie, is not
|
|
a <CODE>bzip2</CODE> data file). This is really a special case of <CODE>BZ_DATA_ERROR</CODE>.
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if insufficient memory was available
|
|
<CODE>BZ_STREAM_END</CODE>
|
|
if the logical end of stream was detected.
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise.
|
|
</PRE>
|
|
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
number of bytes read
|
|
if <CODE>bzerror</CODE> is <CODE>BZ_OK</CODE> or <CODE>BZ_STREAM_END</CODE>
|
|
undefined
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
collect data from <CODE>buf</CODE>, then <CODE>bzRead</CODE> or <CODE>bzReadClose</CODE>
|
|
if <CODE>bzerror</CODE> is <CODE>BZ_OK</CODE>
|
|
collect data from <CODE>buf</CODE>, then <CODE>bzReadClose</CODE> or <CODE>bzReadGetUnused</CODE>
|
|
if <CODE>bzerror</CODE> is <CODE>BZ_SEQUENCE_END</CODE>
|
|
<CODE>bzReadClose</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC19" HREF="manual_toc.html#TOC19"><CODE>bzReadGetUnused</CODE></A></H3>
|
|
|
|
<PRE>
|
|
void bzReadGetUnused ( int* bzerror, BZFILE *b,
|
|
void** unused, int* nUnused );
|
|
</PRE>
|
|
|
|
<P>
|
|
Returns data which was read from the compressed file but was not needed
|
|
to get to the logical end-of-stream. <CODE>*unused</CODE> is set to the address
|
|
of the data, and <CODE>*nUnused</CODE> to the number of bytes. <CODE>*nUnused</CODE> will
|
|
be set to a value between <CODE>0</CODE> and <CODE>BZ_MAX_UNUSED</CODE> inclusive.
|
|
|
|
</P>
|
|
<P>
|
|
This function may only be called once <CODE>bzRead</CODE> has signalled
|
|
<CODE>BZ_STREAM_END</CODE> but before <CODE>bzReadClose</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Possible assignments to <CODE>bzerror</CODE>:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>b</CODE> is <CODE>NULL</CODE>
|
|
or <CODE>unused</CODE> is <CODE>NULL</CODE> or <CODE>nUnused</CODE> is <CODE>NULL</CODE>
|
|
<CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
if <CODE>BZ_STREAM_END</CODE> has not been signalled
|
|
or if <CODE>b</CODE> was opened with <CODE>bzWriteOpen</CODE>
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
<CODE>bzReadClose</CODE>
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC20" HREF="manual_toc.html#TOC20"><CODE>bzReadClose</CODE></A></H3>
|
|
|
|
<PRE>
|
|
void bzReadClose ( int *bzerror, BZFILE *b );
|
|
</PRE>
|
|
|
|
<P>
|
|
Releases all memory pertaining to the compressed file <CODE>b</CODE>.
|
|
<CODE>bzReadClose</CODE> does not call <CODE>fclose</CODE> on the underlying file
|
|
handle, so you should do that yourself if appropriate.
|
|
<CODE>bzReadClose</CODE> should be called to clean up after all error
|
|
situations.
|
|
|
|
</P>
|
|
<P>
|
|
Possible assignments to <CODE>bzerror</CODE>:
|
|
|
|
<PRE>
|
|
<CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
if <CODE>b</CODE> was opened with <CODE>bzOpenWrite</CODE>
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
none
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC21" HREF="manual_toc.html#TOC21"><CODE>bzWriteOpen</CODE></A></H3>
|
|
|
|
<PRE>
|
|
BZFILE *bzWriteOpen ( int *bzerror, FILE *f,
|
|
int blockSize100k, int verbosity,
|
|
int workFactor );
|
|
</PRE>
|
|
|
|
<P>
|
|
Prepare to write compressed data to file handle <CODE>f</CODE>.
|
|
<CODE>f</CODE> should refer to
|
|
a file which has been opened for writing, and for which the error
|
|
indicator (<CODE>ferror(f)</CODE>)is not set.
|
|
|
|
</P>
|
|
<P>
|
|
For the meaning of parameters <CODE>blockSize100k</CODE>,
|
|
<CODE>verbosity</CODE> and <CODE>workFactor</CODE>, see
|
|
<BR> <CODE>bzCompressInit</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
All required memory is allocated at this stage, so if the call
|
|
completes successfully, <CODE>BZ_MEM_ERROR</CODE> cannot be signalled by a
|
|
subsequent call to <CODE>bzWrite</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Possible assignments to <CODE>bzerror</CODE>:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>f</CODE> is <CODE>NULL</CODE>
|
|
or <CODE>blockSize100k < 1</CODE> or <CODE>blockSize100k > 9</CODE>
|
|
<CODE>BZ_IO_ERROR</CODE>
|
|
if <CODE>ferror(f)</CODE> is nonzero
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if insufficient memory is available
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
Pointer to an abstract <CODE>BZFILE</CODE>
|
|
if <CODE>bzerror</CODE> is <CODE>BZ_OK</CODE>
|
|
<CODE>NULL</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
<P>
|
|
Allowable next actions:
|
|
|
|
<PRE>
|
|
<CODE>bzWrite</CODE>
|
|
if <CODE>bzerror</CODE> is <CODE>BZ_OK</CODE>
|
|
(you could go directly to <CODE>bzWriteClose</CODE>, but this would be pretty pointless)
|
|
<CODE>bzWriteClose</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC22" HREF="manual_toc.html#TOC22"><CODE>bzWrite</CODE></A></H3>
|
|
|
|
<PRE>
|
|
void bzWrite ( int *bzerror, BZFILE *b, void *buf, int len );
|
|
</PRE>
|
|
|
|
<P>
|
|
Absorbs <CODE>len</CODE> bytes from the buffer <CODE>buf</CODE>, eventually to be
|
|
compressed and written to the file.
|
|
|
|
</P>
|
|
<P>
|
|
Possible assignments to <CODE>bzerror</CODE>:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>b</CODE> is <CODE>NULL</CODE> or <CODE>buf</CODE> is <CODE>NULL</CODE> or <CODE>len < 0</CODE>
|
|
<CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
if b was opened with <CODE>bzReadOpen</CODE>
|
|
<CODE>BZ_IO_ERROR</CODE>
|
|
if there is an error writing the compressed file.
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC23" HREF="manual_toc.html#TOC23"><CODE>bzWriteClose</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzWriteClose ( int *bzerror, BZFILE* f,
|
|
int abandon,
|
|
unsigned int* nbytes_in,
|
|
unsigned int* nbytes_out );
|
|
</PRE>
|
|
|
|
<P>
|
|
Compresses and flushes to the compressed file all data so far supplied
|
|
by <CODE>bzWrite</CODE>. The logical end-of-stream markers are also written, so
|
|
subsequent calls to <CODE>bzWrite</CODE> are illegal. All memory associated
|
|
with the compressed file <CODE>b</CODE> is released.
|
|
<CODE>fflush</CODE> is called on the
|
|
compressed file, but it is not <CODE>fclose</CODE>'d.
|
|
|
|
</P>
|
|
<P>
|
|
If <CODE>bzWriteClose</CODE> is called to clean up after an error, the only
|
|
action is to release the memory. The library records the error codes
|
|
issued by previous calls, so this situation will be detected
|
|
automatically. There is no attempt to complete the compression
|
|
operation, nor to <CODE>fflush</CODE> the compressed file. You can force this
|
|
behaviour to happen even in the case of no error, by passing a nonzero
|
|
value to <CODE>abandon</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
If <CODE>nbytes_in</CODE> is non-null, <CODE>*nbytes_in</CODE> will be set to be the
|
|
total volume of uncompressed data handled. Similarly, <CODE>nbytes_out</CODE>
|
|
will be set to the total volume of compressed data written.
|
|
|
|
</P>
|
|
<P>
|
|
Possible assignments to <CODE>bzerror</CODE>:
|
|
|
|
<PRE>
|
|
<CODE>BZ_SEQUENCE_ERROR</CODE>
|
|
if <CODE>b</CODE> was opened with <CODE>bzReadOpen</CODE>
|
|
<CODE>BZ_IO_ERROR</CODE>
|
|
if there is an error writing the compressed file
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC24" HREF="manual_toc.html#TOC24">Handling embedded compressed data streams</A></H3>
|
|
|
|
<P>
|
|
The high-level library facilitates use of
|
|
<CODE>bzip2</CODE> data streams which form some part of a surrounding, larger
|
|
data stream.
|
|
|
|
<UL>
|
|
<LI>For writing, the library takes an open file handle, writes
|
|
|
|
compressed data to it, <CODE>fflush</CODE>es it but does not <CODE>fclose</CODE> it.
|
|
The calling application can write its own data before and after the
|
|
compressed data stream, using that same file handle.
|
|
<LI>Reading is more complex, and the facilities are not as general
|
|
|
|
as they could be since generality is hard to reconcile with efficiency.
|
|
<CODE>bzRead</CODE> reads from the compressed file in blocks of size
|
|
<CODE>BZ_MAX_UNUSED</CODE> bytes, and in doing so probably will overshoot
|
|
the logical end of compressed stream.
|
|
To recover this data once decompression has
|
|
ended, call <CODE>bzReadGetUnused</CODE> after the last call of <CODE>bzRead</CODE>
|
|
(the one returning <CODE>BZ_STREAM_END</CODE>) but before calling
|
|
<CODE>bzReadClose</CODE>.
|
|
</UL>
|
|
|
|
<P>
|
|
This mechanism makes it easy to decompress multiple <CODE>bzip2</CODE>
|
|
streams placed end-to-end. As the end of one stream, when <CODE>bzRead</CODE>
|
|
returns <CODE>BZ_STREAM_END</CODE>, call <CODE>bzReadGetUnused</CODE> to collect the
|
|
unused data (copy it into your own buffer somewhere).
|
|
That data forms the start of the next compressed stream.
|
|
To start uncompressing that next stream, call <CODE>bzReadOpen</CODE> again,
|
|
feeding in the unused data via the <CODE>unused</CODE>/<CODE>nUnused</CODE>
|
|
parameters.
|
|
Keep doing this until <CODE>BZ_STREAM_END</CODE> return coincides with the
|
|
physical end of file (<CODE>feof(f)</CODE>). In this situation
|
|
<CODE>bzReadGetUnused</CODE>
|
|
will of course return no data.
|
|
|
|
</P>
|
|
<P>
|
|
This should give some feel for how the high-level interface can be used.
|
|
If you require extra flexibility, you'll have to bite the bullet and get
|
|
to grips with the low-level interface.
|
|
|
|
</P>
|
|
|
|
|
|
<H3><A NAME="SEC25" HREF="manual_toc.html#TOC25">Standard file-reading/writing code</A></H3>
|
|
<P>
|
|
Here's how you'd write data to a compressed file:
|
|
|
|
<PRE>
|
|
FILE* f;
|
|
BZFILE* b;
|
|
int nBuf;
|
|
char buf[ /* whatever size you like */ ];
|
|
int bzerror;
|
|
int nWritten;
|
|
|
|
f = fopen ( "myfile.bz2", "w" );
|
|
if (!f) {
|
|
/* handle error */
|
|
}
|
|
b = bzWriteOpen ( &bzerror, f, 9 );
|
|
if (bzerror != BZ_OK) {
|
|
bzWriteClose ( b );
|
|
/* handle error */
|
|
}
|
|
|
|
while ( /* condition */ ) {
|
|
/* get data to write into buf, and set nBuf appropriately */
|
|
nWritten = bzWrite ( &bzerror, b, buf, nBuf );
|
|
if (bzerror == BZ_IO_ERROR) {
|
|
bzWriteClose ( &bzerror, b );
|
|
/* handle error */
|
|
}
|
|
}
|
|
|
|
bzWriteClose ( &bzerror, b );
|
|
if (bzerror == BZ_IO_ERROR) {
|
|
/* handle error */
|
|
}
|
|
</PRE>
|
|
|
|
<P>
|
|
And to read from a compressed file:
|
|
|
|
<PRE>
|
|
FILE* f;
|
|
BZFILE* b;
|
|
int nBuf;
|
|
char buf[ /* whatever size you like */ ];
|
|
int bzerror;
|
|
int nWritten;
|
|
|
|
f = fopen ( "myfile.bz2", "r" );
|
|
if (!f) {
|
|
/* handle error */
|
|
}
|
|
b = bzReadOpen ( &bzerror, f, 0, NULL, 0 );
|
|
if (bzerror != BZ_OK) {
|
|
bzReadClose ( &bzerror, b );
|
|
/* handle error */
|
|
}
|
|
|
|
bzerror = BZ_OK;
|
|
while (bzerror == BZ_OK && /* arbitrary other conditions */) {
|
|
nBuf = bzRead ( &bzerror, b, buf, /* size of buf */ );
|
|
if (bzerror == BZ_OK) {
|
|
/* do something with buf[0 .. nBuf-1] */
|
|
}
|
|
}
|
|
if (bzerror != BZ_STREAM_END) {
|
|
bzReadClose ( &bzerror, b );
|
|
/* handle error */
|
|
} else {
|
|
bzReadClose ( &bzerror );
|
|
}
|
|
</PRE>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC26" HREF="manual_toc.html#TOC26">Utility functions</A></H2>
|
|
|
|
|
|
<H3><A NAME="SEC27" HREF="manual_toc.html#TOC27"><CODE>bzBuffToBuffCompress</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzBuffToBuffCompress( char* dest,
|
|
unsigned int* destLen,
|
|
char* source,
|
|
unsigned int sourceLen,
|
|
int blockSize100k,
|
|
int verbosity,
|
|
int workFactor );
|
|
</PRE>
|
|
|
|
<P>
|
|
Attempts to compress the data in <CODE>source[0 .. sourceLen-1]</CODE>
|
|
into the destination buffer, <CODE>dest[0 .. *destLen-1]</CODE>.
|
|
If the destination buffer is big enough, <CODE>*destLen</CODE> is
|
|
set to the size of the compressed data, and <CODE>BZ_OK</CODE> is
|
|
returned. If the compressed data won't fit, <CODE>*destLen</CODE>
|
|
is unchanged, and <CODE>BZ_OUTBUFF_FULL</CODE> is returned.
|
|
|
|
</P>
|
|
<P>
|
|
Compression in this manner is a one-shot event, done with a single call
|
|
to this function. The resulting compressed data is a complete
|
|
<CODE>bzip2</CODE> format data stream. There is no mechanism for making
|
|
additional calls to provide extra input data. If you want that kind of
|
|
mechanism, use the low-level interface.
|
|
|
|
</P>
|
|
<P>
|
|
For the meaning of parameters <CODE>blockSize100k</CODE>, <CODE>verbosity</CODE>
|
|
and <CODE>workFactor</CODE>, <BR> see <CODE>bzCompressInit</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
To guarantee that the compressed data will fit in its buffer, allocate
|
|
an output buffer of size 1% larger than the uncompressed data, plus
|
|
fifty bytes.
|
|
|
|
</P>
|
|
<P>
|
|
<CODE>bzBuffToBuffDecompress</CODE> will not write data at or
|
|
beyond <CODE>dest[*destLen]</CODE>, even in case of buffer overflow.
|
|
|
|
</P>
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>dest</CODE> is <CODE>NULL</CODE> or <CODE>destLen</CODE> is <CODE>NULL</CODE>
|
|
or <CODE>blockSize100k < 1</CODE> or <CODE>blockSize100k > 9</CODE>
|
|
or <CODE>verbosity < 0</CODE> or <CODE>verbosity > 4</CODE>
|
|
or <CODE>workFactor < 0</CODE> or <CODE>workFactor > 250</CODE>
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if insufficient memory is available
|
|
<CODE>BZ_OUTBUFF_FULL</CODE>
|
|
if the size of the compressed data exceeds <CODE>*destLen</CODE>
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC28" HREF="manual_toc.html#TOC28"><CODE>bzBuffToBuffDecompress</CODE></A></H3>
|
|
|
|
<PRE>
|
|
int bzBuffToBuffDecompress ( char* dest,
|
|
unsigned int* destLen,
|
|
char* source,
|
|
unsigned int sourceLen,
|
|
int small,
|
|
int verbosity );
|
|
</PRE>
|
|
|
|
<P>
|
|
Attempts to decompress the data in <CODE>source[0 .. sourceLen-1]</CODE>
|
|
into the destination buffer, <CODE>dest[0 .. *destLen-1]</CODE>.
|
|
If the destination buffer is big enough, <CODE>*destLen</CODE> is
|
|
set to the size of the uncompressed data, and <CODE>BZ_OK</CODE> is
|
|
returned. If the compressed data won't fit, <CODE>*destLen</CODE>
|
|
is unchanged, and <CODE>BZ_OUTBUFF_FULL</CODE> is returned.
|
|
|
|
</P>
|
|
<P>
|
|
<CODE>source</CODE> is assumed to hold a complete <CODE>bzip2</CODE> format
|
|
data stream. <CODE>bzBuffToBuffDecompress</CODE> tries to decompress
|
|
the entirety of the stream into the output buffer.
|
|
|
|
</P>
|
|
<P>
|
|
For the meaning of parameters <CODE>small</CODE> and <CODE>verbosity</CODE>,
|
|
see <CODE>bzDecompressInit</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Because the compression ratio of the compressed data cannot be known in
|
|
advance, there is no easy way to guarantee that the output buffer will
|
|
be big enough. You may of course make arrangements in your code to
|
|
record the size of the uncompressed data, but such a mechanism is beyond
|
|
the scope of this library.
|
|
|
|
</P>
|
|
<P>
|
|
<CODE>bzBuffToBuffDecompress</CODE> will not write data at or
|
|
beyond <CODE>dest[*destLen]</CODE>, even in case of buffer overflow.
|
|
|
|
</P>
|
|
<P>
|
|
Possible return values:
|
|
|
|
<PRE>
|
|
<CODE>BZ_PARAM_ERROR</CODE>
|
|
if <CODE>dest</CODE> is <CODE>NULL</CODE> or <CODE>destLen</CODE> is <CODE>NULL</CODE>
|
|
or <CODE>small != 0 && small != 1</CODE>
|
|
or <CODE>verbosity < 0</CODE> or <CODE>verbosity > 4</CODE>
|
|
<CODE>BZ_MEM_ERROR</CODE>
|
|
if insufficient memory is available
|
|
<CODE>BZ_OUTBUFF_FULL</CODE>
|
|
if the size of the compressed data exceeds <CODE>*destLen</CODE>
|
|
<CODE>BZ_DATA_ERROR</CODE>
|
|
if a data integrity error was detected in the compressed data
|
|
<CODE>BZ_DATA_ERROR_MAGIC</CODE>
|
|
if the compressed data doesn't begin with the right magic bytes
|
|
<CODE>BZ_UNEXPECTED_EOF</CODE>
|
|
if the compressed data ends unexpectedly
|
|
<CODE>BZ_OK</CODE>
|
|
otherwise
|
|
</PRE>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC29" HREF="manual_toc.html#TOC29">Using the library in a <CODE>stdio</CODE>-free environment</A></H2>
|
|
|
|
|
|
|
|
<H3><A NAME="SEC30" HREF="manual_toc.html#TOC30">Getting rid of <CODE>stdio</CODE></A></H3>
|
|
|
|
<P>
|
|
In a deeply embedded application, you might want to use just
|
|
the memory-to-memory functions. You can do this conveniently
|
|
by compiling the library with preprocessor symbol <CODE>BZ_NO_STDIO</CODE>
|
|
defined. Doing this gives you a library containing only the following
|
|
eight functions:
|
|
|
|
</P>
|
|
<P>
|
|
<CODE>bzCompressInit</CODE>, <CODE>bzCompress</CODE>, <CODE>bzCompressEnd</CODE> <BR>
|
|
<CODE>bzDecompressInit</CODE>, <CODE>bzDecompress</CODE>, <CODE>bzDecompressEnd</CODE> <BR>
|
|
<CODE>bzBuffToBuffCompress</CODE>, <CODE>bzBuffToBuffDecompress</CODE>
|
|
|
|
</P>
|
|
<P>
|
|
When compiled like this, all functions will ignore <CODE>verbosity</CODE>
|
|
settings.
|
|
|
|
</P>
|
|
|
|
|
|
<H3><A NAME="SEC31" HREF="manual_toc.html#TOC31">Critical error handling</A></H3>
|
|
<P>
|
|
<CODE>libbzip2</CODE> contains a number of internal assertion checks which
|
|
should, needless to say, never be activated. Nevertheless, if an
|
|
assertion should fail, behaviour depends on whether or not the library
|
|
was compiled with <CODE>BZ_NO_STDIO</CODE> set.
|
|
|
|
</P>
|
|
<P>
|
|
For a normal compile, an assertion failure yields the message
|
|
|
|
<PRE>
|
|
bzip2/libbzip2, v0.9.0: internal error number N.
|
|
This is a bug in bzip2/libbzip2, v0.9.0. Please report
|
|
it to me at: jseward@acm.org. If this happened when
|
|
you were using some program which uses libbzip2 as a
|
|
component, you should also report this bug to the author(s)
|
|
of that program. Please make an effort to report this bug;
|
|
timely and accurate bug reports eventually lead to higher
|
|
quality software. Thx. Julian Seward, 27 June 1998.
|
|
</PRE>
|
|
|
|
<P>
|
|
where <CODE>N</CODE> is some error code number. <CODE>exit(3)</CODE>
|
|
is then called.
|
|
|
|
</P>
|
|
<P>
|
|
For a <CODE>stdio</CODE>-free library, assertion failures result
|
|
in a call to a function declared as:
|
|
|
|
<PRE>
|
|
extern void bz_internal_error ( int errcode );
|
|
</PRE>
|
|
|
|
<P>
|
|
The relevant code is passed as a parameter. You should supply
|
|
such a function.
|
|
|
|
</P>
|
|
<P>
|
|
In either case, once an assertion failure has occurred, any
|
|
<CODE>bz_stream</CODE> records involved can be regarded as invalid.
|
|
You should not attempt to resume normal operation with them.
|
|
|
|
</P>
|
|
<P>
|
|
You may, of course, change critical error handling to suit
|
|
your needs. As I said above, critical errors indicate bugs
|
|
in the library and should not occur. All "normal" error
|
|
situations are indicated via error return codes from functions,
|
|
and can be recovered from.
|
|
|
|
</P>
|
|
|
|
|
|
|
|
<H2><A NAME="SEC32" HREF="manual_toc.html#TOC32">Making a Windows DLL</A></H2>
|
|
<P>
|
|
Everything related to Windows has been contributed by Yoshioka Tsuneo
|
|
<BR> (<CODE>QWF00133@niftyserve.or.jp</CODE> /
|
|
<CODE>tsuneo-y@is.aist-nara.ac.jp</CODE>), so you should send your queries to
|
|
him (but perhaps Cc: me, <CODE>jseward@acm.org</CODE>).
|
|
|
|
</P>
|
|
<P>
|
|
My vague understanding of what to do is: using Visual C++ 5.0,
|
|
open the project file <CODE>libbz2.dsp</CODE>, and build. That's all.
|
|
|
|
</P>
|
|
<P>
|
|
If you can't
|
|
open the project file for some reason, make a new one, naming these files:
|
|
<CODE>blocksort.c</CODE>, <CODE>bzlib.c</CODE>, <CODE>compress.c</CODE>,
|
|
<CODE>crctable.c</CODE>, <CODE>decompress.c</CODE>, <CODE>huffman.c</CODE>, <BR>
|
|
<CODE>randtable.c</CODE> and <CODE>libbz2.def</CODE>. You might also need
|
|
to name the header files <CODE>bzlib.h</CODE> and <CODE>bzlib_private.h</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
If you don't use VC++, you may need to define the proprocessor symbol
|
|
<CODE>_WIN32</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
Finally, <CODE>dlltest.c</CODE> is a sample program using the DLL. It has a
|
|
project file, <CODE>dlltest.dsp</CODE>.
|
|
|
|
</P>
|
|
<P>
|
|
I haven't tried any of this stuff myself, but it all looks plausible.
|
|
|
|
</P>
|
|
|
|
<P><HR><P>
|
|
Go to the <A HREF="manual_1.html">first</A>, <A HREF="manual_2.html">previous</A>, <A HREF="manual_4.html">next</A>, <A HREF="manual_4.html">last</A> section, <A HREF="manual_toc.html">table of contents</A>.
|
|
</BODY>
|
|
</HTML>
|