Chris@43: Chris@43: Chris@43: Chris@43: Chris@43: zlib Usage Example Chris@43: Chris@43: Chris@43: Chris@43:

zlib Usage Example

Chris@43: We often get questions about how the deflate() and inflate() functions should be used. Chris@43: Users wonder when they should provide more input, when they should use more output, Chris@43: what to do with a Z_BUF_ERROR, how to make sure the process terminates properly, and Chris@43: so on. So for those who have read zlib.h (a few times), and Chris@43: would like further edification, below is an annotated example in C of simple routines to compress and decompress Chris@43: from an input file to an output file using deflate() and inflate() respectively. The Chris@43: annotations are interspersed between lines of the code. So please read between the lines. Chris@43: We hope this helps explain some of the intricacies of zlib. Chris@43:

Chris@43: Without further adieu, here is the program zpipe.c: Chris@43:


Chris@43: /* zpipe.c: example of proper use of zlib's inflate() and deflate()
Chris@43:    Not copyrighted -- provided to the public domain
Chris@43:    Version 1.4  11 December 2005  Mark Adler */
Chris@43: 
Chris@43: /* Version history:
Chris@43:    1.0  30 Oct 2004  First version
Chris@43:    1.1   8 Nov 2004  Add void casting for unused return values
Chris@43:                      Use switch statement for inflate() return values
Chris@43:    1.2   9 Nov 2004  Add assertions to document zlib guarantees
Chris@43:    1.3   6 Apr 2005  Remove incorrect assertion in inf()
Chris@43:    1.4  11 Dec 2005  Add hack to avoid MSDOS end-of-line conversions
Chris@43:                      Avoid some compiler warnings for input and output buffers
Chris@43:  */
Chris@43: 
Chris@43: We now include the header files for the required definitions. From Chris@43: stdio.h we use fopen(), fread(), fwrite(), Chris@43: feof(), ferror(), and fclose() for file i/o, and Chris@43: fputs() for error messages. From string.h we use Chris@43: strcmp() for command line argument processing. Chris@43: From assert.h we use the assert() macro. Chris@43: From zlib.h Chris@43: we use the basic compression functions deflateInit(), Chris@43: deflate(), and deflateEnd(), and the basic decompression Chris@43: functions inflateInit(), inflate(), and Chris@43: inflateEnd(). Chris@43:

Chris@43: #include <stdio.h>
Chris@43: #include <string.h>
Chris@43: #include <assert.h>
Chris@43: #include "zlib.h"
Chris@43: 
Chris@43: This is an ugly hack required to avoid corruption of the input and output data on Chris@43: Windows/MS-DOS systems. Without this, those systems would assume that the input and output Chris@43: files are text, and try to convert the end-of-line characters from one standard to Chris@43: another. That would corrupt binary data, and in particular would render the compressed data unusable. Chris@43: This sets the input and output to binary which suppresses the end-of-line conversions. Chris@43: SET_BINARY_MODE() will be used later on stdin and stdout, at the beginning of main(). Chris@43:

Chris@43: #if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(__CYGWIN__)
Chris@43: #  include <fcntl.h>
Chris@43: #  include <io.h>
Chris@43: #  define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY)
Chris@43: #else
Chris@43: #  define SET_BINARY_MODE(file)
Chris@43: #endif
Chris@43: 
Chris@43: CHUNK is simply the buffer size for feeding data to and pulling data Chris@43: from the zlib routines. Larger buffer sizes would be more efficient, Chris@43: especially for inflate(). If the memory is available, buffers sizes Chris@43: on the order of 128K or 256K bytes should be used. Chris@43:

Chris@43: #define CHUNK 16384
Chris@43: 
Chris@43: The def() routine compresses data from an input file to an output file. The output data Chris@43: will be in the zlib format, which is different from the gzip or zip Chris@43: formats. The zlib format has a very small header of only two bytes to identify it as Chris@43: a zlib stream and to provide decoding information, and a four-byte trailer with a fast Chris@43: check value to verify the integrity of the uncompressed data after decoding. Chris@43:

Chris@43: /* Compress from file source to file dest until EOF on source.
Chris@43:    def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
Chris@43:    allocated for processing, Z_STREAM_ERROR if an invalid compression
Chris@43:    level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
Chris@43:    version of the library linked do not match, or Z_ERRNO if there is
Chris@43:    an error reading or writing the files. */
Chris@43: int def(FILE *source, FILE *dest, int level)
Chris@43: {
Chris@43: 
Chris@43: Here are the local variables for def(). ret will be used for zlib Chris@43: return codes. flush will keep track of the current flushing state for deflate(), Chris@43: which is either no flushing, or flush to completion after the end of the input file is reached. Chris@43: have is the amount of data returned from deflate(). The strm structure Chris@43: is used to pass information to and from the zlib routines, and to maintain the Chris@43: deflate() state. in and out are the input and output buffers for Chris@43: deflate(). Chris@43:

Chris@43:     int ret, flush;
Chris@43:     unsigned have;
Chris@43:     z_stream strm;
Chris@43:     unsigned char in[CHUNK];
Chris@43:     unsigned char out[CHUNK];
Chris@43: 
Chris@43: The first thing we do is to initialize the zlib state for compression using Chris@43: deflateInit(). This must be done before the first use of deflate(). Chris@43: The zalloc, zfree, and opaque fields in the strm Chris@43: structure must be initialized before calling deflateInit(). Here they are Chris@43: set to the zlib constant Z_NULL to request that zlib use Chris@43: the default memory allocation routines. An application may also choose to provide Chris@43: custom memory allocation routines here. deflateInit() will allocate on the Chris@43: order of 256K bytes for the internal state. Chris@43: (See zlib Technical Details.) Chris@43:

Chris@43: deflateInit() is called with a pointer to the structure to be initialized and Chris@43: the compression level, which is an integer in the range of -1 to 9. Lower compression Chris@43: levels result in faster execution, but less compression. Higher levels result in Chris@43: greater compression, but slower execution. The zlib constant Z_DEFAULT_COMPRESSION, Chris@43: equal to -1, Chris@43: provides a good compromise between compression and speed and is equivalent to level 6. Chris@43: Level 0 actually does no compression at all, and in fact expands the data slightly to produce Chris@43: the zlib format (it is not a byte-for-byte copy of the input). Chris@43: More advanced applications of zlib Chris@43: may use deflateInit2() here instead. Such an application may want to reduce how Chris@43: much memory will be used, at some price in compression. Or it may need to request a Chris@43: gzip header and trailer instead of a zlib header and trailer, or raw Chris@43: encoding with no header or trailer at all. Chris@43:

Chris@43: We must check the return value of deflateInit() against the zlib constant Chris@43: Z_OK to make sure that it was able to Chris@43: allocate memory for the internal state, and that the provided arguments were valid. Chris@43: deflateInit() will also check that the version of zlib that the zlib.h Chris@43: file came from matches the version of zlib actually linked with the program. This Chris@43: is especially important for environments in which zlib is a shared library. Chris@43:

Chris@43: Note that an application can initialize multiple, independent zlib streams, which can Chris@43: operate in parallel. The state information maintained in the structure allows the zlib Chris@43: routines to be reentrant. Chris@43:


Chris@43:     /* allocate deflate state */
Chris@43:     strm.zalloc = Z_NULL;
Chris@43:     strm.zfree = Z_NULL;
Chris@43:     strm.opaque = Z_NULL;
Chris@43:     ret = deflateInit(&strm, level);
Chris@43:     if (ret != Z_OK)
Chris@43:         return ret;
Chris@43: 
Chris@43: With the pleasantries out of the way, now we can get down to business. The outer do-loop Chris@43: reads all of the input file and exits at the bottom of the loop once end-of-file is reached. Chris@43: This loop contains the only call of deflate(). So we must make sure that all of the Chris@43: input data has been processed and that all of the output data has been generated and consumed Chris@43: before we fall out of the loop at the bottom. Chris@43:

Chris@43:     /* compress until end of file */
Chris@43:     do {
Chris@43: 
Chris@43: We start off by reading data from the input file. The number of bytes read is put directly Chris@43: into avail_in, and a pointer to those bytes is put into next_in. We also Chris@43: check to see if end-of-file on the input has been reached. If we are at the end of file, then flush is set to the Chris@43: zlib constant Z_FINISH, which is later passed to deflate() to Chris@43: indicate that this is the last chunk of input data to compress. We need to use feof() Chris@43: to check for end-of-file as opposed to seeing if fewer than CHUNK bytes have been read. The Chris@43: reason is that if the input file length is an exact multiple of CHUNK, we will miss Chris@43: the fact that we got to the end-of-file, and not know to tell deflate() to finish Chris@43: up the compressed stream. If we are not yet at the end of the input, then the zlib Chris@43: constant Z_NO_FLUSH will be passed to deflate to indicate that we are still Chris@43: in the middle of the uncompressed data. Chris@43:

Chris@43: If there is an error in reading from the input file, the process is aborted with Chris@43: deflateEnd() being called to free the allocated zlib state before returning Chris@43: the error. We wouldn't want a memory leak, now would we? deflateEnd() can be called Chris@43: at any time after the state has been initialized. Once that's done, deflateInit() (or Chris@43: deflateInit2()) would have to be called to start a new compression process. There is Chris@43: no point here in checking the deflateEnd() return code. The deallocation can't fail. Chris@43:


Chris@43:         strm.avail_in = fread(in, 1, CHUNK, source);
Chris@43:         if (ferror(source)) {
Chris@43:             (void)deflateEnd(&strm);
Chris@43:             return Z_ERRNO;
Chris@43:         }
Chris@43:         flush = feof(source) ? Z_FINISH : Z_NO_FLUSH;
Chris@43:         strm.next_in = in;
Chris@43: 
Chris@43: The inner do-loop passes our chunk of input data to deflate(), and then Chris@43: keeps calling deflate() until it is done producing output. Once there is no more Chris@43: new output, deflate() is guaranteed to have consumed all of the input, i.e., Chris@43: avail_in will be zero. Chris@43:

Chris@43:         /* run deflate() on input until output buffer not full, finish
Chris@43:            compression if all of source has been read in */
Chris@43:         do {
Chris@43: 
Chris@43: Output space is provided to deflate() by setting avail_out to the number Chris@43: of available output bytes and next_out to a pointer to that space. Chris@43:

Chris@43:             strm.avail_out = CHUNK;
Chris@43:             strm.next_out = out;
Chris@43: 
Chris@43: Now we call the compression engine itself, deflate(). It takes as many of the Chris@43: avail_in bytes at next_in as it can process, and writes as many as Chris@43: avail_out bytes to next_out. Those counters and pointers are then Chris@43: updated past the input data consumed and the output data written. It is the amount of Chris@43: output space available that may limit how much input is consumed. Chris@43: Hence the inner loop to make sure that Chris@43: all of the input is consumed by providing more output space each time. Since avail_in Chris@43: and next_in are updated by deflate(), we don't have to mess with those Chris@43: between deflate() calls until it's all used up. Chris@43:

Chris@43: The parameters to deflate() are a pointer to the strm structure containing Chris@43: the input and output information and the internal compression engine state, and a parameter Chris@43: indicating whether and how to flush data to the output. Normally deflate will consume Chris@43: several K bytes of input data before producing any output (except for the header), in order Chris@43: to accumulate statistics on the data for optimum compression. It will then put out a burst of Chris@43: compressed data, and proceed to consume more input before the next burst. Eventually, Chris@43: deflate() Chris@43: must be told to terminate the stream, complete the compression with provided input data, and Chris@43: write out the trailer check value. deflate() will continue to compress normally as long Chris@43: as the flush parameter is Z_NO_FLUSH. Once the Z_FINISH parameter is provided, Chris@43: deflate() will begin to complete the compressed output stream. However depending on how Chris@43: much output space is provided, deflate() may have to be called several times until it Chris@43: has provided the complete compressed stream, even after it has consumed all of the input. The flush Chris@43: parameter must continue to be Z_FINISH for those subsequent calls. Chris@43:

Chris@43: There are other values of the flush parameter that are used in more advanced applications. You can Chris@43: force deflate() to produce a burst of output that encodes all of the input data provided Chris@43: so far, even if it wouldn't have otherwise, for example to control data latency on a link with Chris@43: compressed data. You can also ask that deflate() do that as well as erase any history up to Chris@43: that point so that what follows can be decompressed independently, for example for random access Chris@43: applications. Both requests will degrade compression by an amount depending on how often such Chris@43: requests are made. Chris@43:

Chris@43: deflate() has a return value that can indicate errors, yet we do not check it here. Why Chris@43: not? Well, it turns out that deflate() can do no wrong here. Let's go through Chris@43: deflate()'s return values and dispense with them one by one. The possible values are Chris@43: Z_OK, Z_STREAM_END, Z_STREAM_ERROR, or Z_BUF_ERROR. Z_OK Chris@43: is, well, ok. Z_STREAM_END is also ok and will be returned for the last call of Chris@43: deflate(). This is already guaranteed by calling deflate() with Z_FINISH Chris@43: until it has no more output. Z_STREAM_ERROR is only possible if the stream is not Chris@43: initialized properly, but we did initialize it properly. There is no harm in checking for Chris@43: Z_STREAM_ERROR here, for example to check for the possibility that some Chris@43: other part of the application inadvertently clobbered the memory containing the zlib state. Chris@43: Z_BUF_ERROR will be explained further below, but Chris@43: suffice it to say that this is simply an indication that deflate() could not consume Chris@43: more input or produce more output. deflate() can be called again with more output space Chris@43: or more available input, which it will be in this code. Chris@43:


Chris@43:             ret = deflate(&strm, flush);    /* no bad return value */
Chris@43:             assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
Chris@43: 
Chris@43: Now we compute how much output deflate() provided on the last call, which is the Chris@43: difference between how much space was provided before the call, and how much output space Chris@43: is still available after the call. Then that data, if any, is written to the output file. Chris@43: We can then reuse the output buffer for the next call of deflate(). Again if there Chris@43: is a file i/o error, we call deflateEnd() before returning to avoid a memory leak. Chris@43:

Chris@43:             have = CHUNK - strm.avail_out;
Chris@43:             if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
Chris@43:                 (void)deflateEnd(&strm);
Chris@43:                 return Z_ERRNO;
Chris@43:             }
Chris@43: 
Chris@43: The inner do-loop is repeated until the last deflate() call fails to fill the Chris@43: provided output buffer. Then we know that deflate() has done as much as it can with Chris@43: the provided input, and that all of that input has been consumed. We can then fall out of this Chris@43: loop and reuse the input buffer. Chris@43:

Chris@43: The way we tell that deflate() has no more output is by seeing that it did not fill Chris@43: the output buffer, leaving avail_out greater than zero. However suppose that Chris@43: deflate() has no more output, but just so happened to exactly fill the output buffer! Chris@43: avail_out is zero, and we can't tell that deflate() has done all it can. Chris@43: As far as we know, deflate() Chris@43: has more output for us. So we call it again. But now deflate() produces no output Chris@43: at all, and avail_out remains unchanged as CHUNK. That deflate() call Chris@43: wasn't able to do anything, either consume input or produce output, and so it returns Chris@43: Z_BUF_ERROR. (See, I told you I'd cover this later.) However this is not a problem at Chris@43: all. Now we finally have the desired indication that deflate() is really done, Chris@43: and so we drop out of the inner loop to provide more input to deflate(). Chris@43:

Chris@43: With flush set to Z_FINISH, this final set of deflate() calls will Chris@43: complete the output stream. Once that is done, subsequent calls of deflate() would return Chris@43: Z_STREAM_ERROR if the flush parameter is not Z_FINISH, and do no more processing Chris@43: until the state is reinitialized. Chris@43:

Chris@43: Some applications of zlib have two loops that call deflate() Chris@43: instead of the single inner loop we have here. The first loop would call Chris@43: without flushing and feed all of the data to deflate(). The second loop would call Chris@43: deflate() with no more Chris@43: data and the Z_FINISH parameter to complete the process. As you can see from this Chris@43: example, that can be avoided by simply keeping track of the current flush state. Chris@43:


Chris@43:         } while (strm.avail_out == 0);
Chris@43:         assert(strm.avail_in == 0);     /* all input will be used */
Chris@43: 
Chris@43: Now we check to see if we have already processed all of the input file. That information was Chris@43: saved in the flush variable, so we see if that was set to Z_FINISH. If so, Chris@43: then we're done and we fall out of the outer loop. We're guaranteed to get Z_STREAM_END Chris@43: from the last deflate() call, since we ran it until the last chunk of input was Chris@43: consumed and all of the output was generated. Chris@43:

Chris@43:         /* done when last data in file processed */
Chris@43:     } while (flush != Z_FINISH);
Chris@43:     assert(ret == Z_STREAM_END);        /* stream will be complete */
Chris@43: 
Chris@43: The process is complete, but we still need to deallocate the state to avoid a memory leak Chris@43: (or rather more like a memory hemorrhage if you didn't do this). Then Chris@43: finally we can return with a happy return value. Chris@43:

Chris@43:     /* clean up and return */
Chris@43:     (void)deflateEnd(&strm);
Chris@43:     return Z_OK;
Chris@43: }
Chris@43: 
Chris@43: Now we do the same thing for decompression in the inf() routine. inf() Chris@43: decompresses what is hopefully a valid zlib stream from the input file and writes the Chris@43: uncompressed data to the output file. Much of the discussion above for def() Chris@43: applies to inf() as well, so the discussion here will focus on the differences between Chris@43: the two. Chris@43:

Chris@43: /* Decompress from file source to file dest until stream ends or EOF.
Chris@43:    inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
Chris@43:    allocated for processing, Z_DATA_ERROR if the deflate data is
Chris@43:    invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
Chris@43:    the version of the library linked do not match, or Z_ERRNO if there
Chris@43:    is an error reading or writing the files. */
Chris@43: int inf(FILE *source, FILE *dest)
Chris@43: {
Chris@43: 
Chris@43: The local variables have the same functionality as they do for def(). The Chris@43: only difference is that there is no flush variable, since inflate() Chris@43: can tell from the zlib stream itself when the stream is complete. Chris@43:

Chris@43:     int ret;
Chris@43:     unsigned have;
Chris@43:     z_stream strm;
Chris@43:     unsigned char in[CHUNK];
Chris@43:     unsigned char out[CHUNK];
Chris@43: 
Chris@43: The initialization of the state is the same, except that there is no compression level, Chris@43: of course, and two more elements of the structure are initialized. avail_in Chris@43: and next_in must be initialized before calling inflateInit(). This Chris@43: is because the application has the option to provide the start of the zlib stream in Chris@43: order for inflateInit() to have access to information about the compression Chris@43: method to aid in memory allocation. In the current implementation of zlib Chris@43: (up through versions 1.2.x), the method-dependent memory allocations are deferred to the first call of Chris@43: inflate() anyway. However those fields must be initialized since later versions Chris@43: of zlib that provide more compression methods may take advantage of this interface. Chris@43: In any case, no decompression is performed by inflateInit(), so the Chris@43: avail_out and next_out fields do not need to be initialized before calling. Chris@43:

Chris@43: Here avail_in is set to zero and next_in is set to Z_NULL to Chris@43: indicate that no input data is being provided. Chris@43:


Chris@43:     /* allocate inflate state */
Chris@43:     strm.zalloc = Z_NULL;
Chris@43:     strm.zfree = Z_NULL;
Chris@43:     strm.opaque = Z_NULL;
Chris@43:     strm.avail_in = 0;
Chris@43:     strm.next_in = Z_NULL;
Chris@43:     ret = inflateInit(&strm);
Chris@43:     if (ret != Z_OK)
Chris@43:         return ret;
Chris@43: 
Chris@43: The outer do-loop decompresses input until inflate() indicates Chris@43: that it has reached the end of the compressed data and has produced all of the uncompressed Chris@43: output. This is in contrast to def() which processes all of the input file. Chris@43: If end-of-file is reached before the compressed data self-terminates, then the compressed Chris@43: data is incomplete and an error is returned. Chris@43:

Chris@43:     /* decompress until deflate stream ends or end of file */
Chris@43:     do {
Chris@43: 
Chris@43: We read input data and set the strm structure accordingly. If we've reached the Chris@43: end of the input file, then we leave the outer loop and report an error, since the Chris@43: compressed data is incomplete. Note that we may read more data than is eventually consumed Chris@43: by inflate(), if the input file continues past the zlib stream. Chris@43: For applications where zlib streams are embedded in other data, this routine would Chris@43: need to be modified to return the unused data, or at least indicate how much of the input Chris@43: data was not used, so the application would know where to pick up after the zlib stream. Chris@43:

Chris@43:         strm.avail_in = fread(in, 1, CHUNK, source);
Chris@43:         if (ferror(source)) {
Chris@43:             (void)inflateEnd(&strm);
Chris@43:             return Z_ERRNO;
Chris@43:         }
Chris@43:         if (strm.avail_in == 0)
Chris@43:             break;
Chris@43:         strm.next_in = in;
Chris@43: 
Chris@43: The inner do-loop has the same function it did in def(), which is to Chris@43: keep calling inflate() until has generated all of the output it can with the Chris@43: provided input. Chris@43:

Chris@43:         /* run inflate() on input until output buffer not full */
Chris@43:         do {
Chris@43: 
Chris@43: Just like in def(), the same output space is provided for each call of inflate(). Chris@43:

Chris@43:             strm.avail_out = CHUNK;
Chris@43:             strm.next_out = out;
Chris@43: 
Chris@43: Now we run the decompression engine itself. There is no need to adjust the flush parameter, since Chris@43: the zlib format is self-terminating. The main difference here is that there are Chris@43: return values that we need to pay attention to. Z_DATA_ERROR Chris@43: indicates that inflate() detected an error in the zlib compressed data format, Chris@43: which means that either the data is not a zlib stream to begin with, or that the data was Chris@43: corrupted somewhere along the way since it was compressed. The other error to be processed is Chris@43: Z_MEM_ERROR, which can occur since memory allocation is deferred until inflate() Chris@43: needs it, unlike deflate(), whose memory is allocated at the start by deflateInit(). Chris@43:

Chris@43: Advanced applications may use Chris@43: deflateSetDictionary() to prime deflate() with a set of likely data to improve the Chris@43: first 32K or so of compression. This is noted in the zlib header, so inflate() Chris@43: requests that that dictionary be provided before it can start to decompress. Without the dictionary, Chris@43: correct decompression is not possible. For this routine, we have no idea what the dictionary is, Chris@43: so the Z_NEED_DICT indication is converted to a Z_DATA_ERROR. Chris@43:

Chris@43: inflate() can also return Z_STREAM_ERROR, which should not be possible here, Chris@43: but could be checked for as noted above for def(). Z_BUF_ERROR does not need to be Chris@43: checked for here, for the same reasons noted for def(). Z_STREAM_END will be Chris@43: checked for later. Chris@43:


Chris@43:             ret = inflate(&strm, Z_NO_FLUSH);
Chris@43:             assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
Chris@43:             switch (ret) {
Chris@43:             case Z_NEED_DICT:
Chris@43:                 ret = Z_DATA_ERROR;     /* and fall through */
Chris@43:             case Z_DATA_ERROR:
Chris@43:             case Z_MEM_ERROR:
Chris@43:                 (void)inflateEnd(&strm);
Chris@43:                 return ret;
Chris@43:             }
Chris@43: 
Chris@43: The output of inflate() is handled identically to that of deflate(). Chris@43:

Chris@43:             have = CHUNK - strm.avail_out;
Chris@43:             if (fwrite(out, 1, have, dest) != have || ferror(dest)) {
Chris@43:                 (void)inflateEnd(&strm);
Chris@43:                 return Z_ERRNO;
Chris@43:             }
Chris@43: 
Chris@43: The inner do-loop ends when inflate() has no more output as indicated Chris@43: by not filling the output buffer, just as for deflate(). In this case, we cannot Chris@43: assert that strm.avail_in will be zero, since the deflate stream may end before the file Chris@43: does. Chris@43:

Chris@43:         } while (strm.avail_out == 0);
Chris@43: 
Chris@43: The outer do-loop ends when inflate() reports that it has reached the Chris@43: end of the input zlib stream, has completed the decompression and integrity Chris@43: check, and has provided all of the output. This is indicated by the inflate() Chris@43: return value Z_STREAM_END. The inner loop is guaranteed to leave ret Chris@43: equal to Z_STREAM_END if the last chunk of the input file read contained the end Chris@43: of the zlib stream. So if the return value is not Z_STREAM_END, the Chris@43: loop continues to read more input. Chris@43:

Chris@43:         /* done when inflate() says it's done */
Chris@43:     } while (ret != Z_STREAM_END);
Chris@43: 
Chris@43: At this point, decompression successfully completed, or we broke out of the loop due to no Chris@43: more data being available from the input file. If the last inflate() return value Chris@43: is not Z_STREAM_END, then the zlib stream was incomplete and a data error Chris@43: is returned. Otherwise, we return with a happy return value. Of course, inflateEnd() Chris@43: is called first to avoid a memory leak. Chris@43:

Chris@43:     /* clean up and return */
Chris@43:     (void)inflateEnd(&strm);
Chris@43:     return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
Chris@43: }
Chris@43: 
Chris@43: That ends the routines that directly use zlib. The following routines make this Chris@43: a command-line program by running data through the above routines from stdin to Chris@43: stdout, and handling any errors reported by def() or inf(). Chris@43:

Chris@43: zerr() is used to interpret the possible error codes from def() Chris@43: and inf(), as detailed in their comments above, and print out an error message. Chris@43: Note that these are only a subset of the possible return values from deflate() Chris@43: and inflate(). Chris@43:


Chris@43: /* report a zlib or i/o error */
Chris@43: void zerr(int ret)
Chris@43: {
Chris@43:     fputs("zpipe: ", stderr);
Chris@43:     switch (ret) {
Chris@43:     case Z_ERRNO:
Chris@43:         if (ferror(stdin))
Chris@43:             fputs("error reading stdin\n", stderr);
Chris@43:         if (ferror(stdout))
Chris@43:             fputs("error writing stdout\n", stderr);
Chris@43:         break;
Chris@43:     case Z_STREAM_ERROR:
Chris@43:         fputs("invalid compression level\n", stderr);
Chris@43:         break;
Chris@43:     case Z_DATA_ERROR:
Chris@43:         fputs("invalid or incomplete deflate data\n", stderr);
Chris@43:         break;
Chris@43:     case Z_MEM_ERROR:
Chris@43:         fputs("out of memory\n", stderr);
Chris@43:         break;
Chris@43:     case Z_VERSION_ERROR:
Chris@43:         fputs("zlib version mismatch!\n", stderr);
Chris@43:     }
Chris@43: }
Chris@43: 
Chris@43: Here is the main() routine used to test def() and inf(). The Chris@43: zpipe command is simply a compression pipe from stdin to stdout, if Chris@43: no arguments are given, or it is a decompression pipe if zpipe -d is used. If any other Chris@43: arguments are provided, no compression or decompression is performed. Instead a usage Chris@43: message is displayed. Examples are zpipe < foo.txt > foo.txt.z to compress, and Chris@43: zpipe -d < foo.txt.z > foo.txt to decompress. Chris@43:

Chris@43: /* compress or decompress from stdin to stdout */
Chris@43: int main(int argc, char **argv)
Chris@43: {
Chris@43:     int ret;
Chris@43: 
Chris@43:     /* avoid end-of-line conversions */
Chris@43:     SET_BINARY_MODE(stdin);
Chris@43:     SET_BINARY_MODE(stdout);
Chris@43: 
Chris@43:     /* do compression if no arguments */
Chris@43:     if (argc == 1) {
Chris@43:         ret = def(stdin, stdout, Z_DEFAULT_COMPRESSION);
Chris@43:         if (ret != Z_OK)
Chris@43:             zerr(ret);
Chris@43:         return ret;
Chris@43:     }
Chris@43: 
Chris@43:     /* do decompression if -d specified */
Chris@43:     else if (argc == 2 && strcmp(argv[1], "-d") == 0) {
Chris@43:         ret = inf(stdin, stdout);
Chris@43:         if (ret != Z_OK)
Chris@43:             zerr(ret);
Chris@43:         return ret;
Chris@43:     }
Chris@43: 
Chris@43:     /* otherwise, report usage */
Chris@43:     else {
Chris@43:         fputs("zpipe usage: zpipe [-d] < source > dest\n", stderr);
Chris@43:         return 1;
Chris@43:     }
Chris@43: }
Chris@43: 
Chris@43:
Chris@43: Copyright (c) 2004, 2005 by Mark Adler
Last modified 11 December 2005
Chris@43: Chris@43: