flate.c

Go to the documentation of this file.
00001 /*
00002  * $Id: flate.c,v 2.0 2004/11/09 12:16:41 bernhard Exp $
00003  *
00004  ****************************************************************************
00005  *                     -- GRASS Development Team --
00006  *
00007  * MODULE:      GRASS gis library
00008  * FILENAME:    flate.c
00009  * AUTHOR(S):   Eric G. Miller <egm2@jps.net>
00010  * PURPOSE:     To provide an interface to libz for compressing and 
00011  *              decompressing data using DEFLATE.  It's primary use is in
00012  *              the storage and reading of GRASS floating point rasters.
00013  *              It replaces the patented LZW compression interface.
00014  *
00015  * ALGORITHM:   http://www.gzip.org/zlib/feldspar.html
00016  * DATE CREATED: Nov 19 2000
00017  * COPYRIGHT:   (C) 2000 by the GRASS Development Team
00018  *
00019  *              This program is free software under the GNU General Public
00020  *              License (version 2 or greater). Read the file COPYING that 
00021  *              comes with GRASS for details.
00022  *
00023  *****************************************************************************/
00024 
00025 /********************************************************************
00026  * int                                                              *
00027  * G_zlib_read (fd, rbytes, dst, nbytes)                            *
00028  *     int fd, rbytes, nbytes;                                      *
00029  *     unsigned char *dst;                                          *
00030  * ---------------------------------------------------------------- *
00031  * This is the basic function for reading a compressed chunk of a   *
00032  * data file.  The file descriptor should be in the proper location *
00033  * and the 'dst' array should have enough space for the data.       *
00034  * 'nbytes' is the size of 'dst'.  The 'rbytes' parameter is the    *
00035  * number of bytes to read (knowable from the offsets index). For   *
00036  * best results, 'nbytes' should be the exact amount of space       *
00037  * needed for the expansion.  Too large a value of nbytes may cause *
00038  * more data to be expanded than is desired.                        *
00039  * Returns: The number of bytes decompressed into dst, or an error. *
00040  *                                                                  *
00041  * Errors include:                                                  *
00042  *        -1  -- Error Reading or Decompressing data.               *
00043  *        -2  -- Not enough space in dst.  You must make dst larger *
00044  *               and then call the function again (remembering to   *
00045  *               reset the file descriptor to it's proper location. *
00046  *                                                                  *
00047  * ================================================================ *
00048  * int                                                              *
00049  * G_zlib_write (fd, src, nbytes)                                   *
00050  *     int fd, nbytes;                                              *
00051  *     unsigned char *src;                                          *
00052  * ---------------------------------------------------------------- *
00053  * This is the basic function for writing and compressing a data    *
00054  * chunk to a file.  The file descriptor should be in the correct   *
00055  * location prior to this call. The function will compress 'nbytes' *
00056  * of 'src' and write it to the file 'fd'.  Returns the number of   *
00057  * bytes written or an error code:                                  *
00058  *                                                                  *
00059  * Errors include:                                                  *
00060  *        -1 -- Compression Failed.                                 *
00061  *        -2 -- Unable to write to file.                            *
00062  *                                                                  *
00063  * ================================================================ *
00064  * int                                                              *
00065  * G_zlib_write_noCompress (fd, src, nbytes)                        *
00066  *     int fd, nbytes;                                              *
00067  *     unsigned char *src;                                          *
00068  * ---------------------------------------------------------------- *
00069  * Works similar to G_zlib_write() except no attempt at compression *
00070  * is made.  This is quicker, but may result in larger files.       *
00071  * Returns the number of bytes written, or -1 for an error. It will *
00072  * return an error if it fails to write nbytes. Otherwise, the      *
00073  * return value will always be nbytes + 1 (for compression flag).   *
00074  *                                                                  *
00075  * ================================================================ *
00076  * int                                                              *
00077  * G_zlib_compress (src, srz_sz, dst, dst_sz)                       *
00078  *     int src_sz, dst_sz;                                          *
00079  *     unsigned char *src, *dst;                                    *
00080  * ---------------------------------------------------------------- *
00081  * This function is a wrapper around the zlib deflate() function.   *
00082  * It uses an all or nothing call to deflate().  If you need a      *
00083  * continuous compression scheme, you'll have to code your own.     *
00084  * In order to do a single pass compression, the input src must be  *
00085  * copied to a buffer 1% + 12 bytes larger than the data.  This may *
00086  * cause performance degradation.                                   *
00087  *                                                                  *
00088  * The function either returns the number of bytes of compressed    *
00089  * data in dst, or an error code.                                   *
00090  *                                                                  *
00091  * Errors include:                                                  *
00092  *        -1 -- Compression failed.                                 *
00093  *        -2 -- dst is too small.                                   *
00094  *                                                                  *
00095  * ================================================================ *
00096  * int                                                              *
00097  * G_zlib_expand (src, src_sz, dst, dst_sz)                         *
00098  *     int src_sz, dst_sz;                                          *
00099  *     unsigned char *src, *dst;                                    *
00100  * ---------------------------------------------------------------- *
00101  * This function is a wrapper around the zlib inflate() function.   *
00102  * It uses a single pass call to inflate().  If you need a contin-  *
00103  * uous expansion scheme, you'll have to code your own.             *
00104  *                                                                  *
00105  * The function returns the number of bytes expanded into 'dst' or  *
00106  * and error code.                                                  *
00107  *                                                                  *
00108  * Errors include:                                                  *
00109  *        -1 -- Expansion failed.                                   *
00110  *                                                                  *
00111  ********************************************************************
00112  */
00113 
00114 #include "config.h"
00115 
00116 #ifndef HAVE_ZLIB_H
00117 
00118 #error "GRASS requires libz to compile"
00119 
00120 #else
00121 
00122 #include <zlib.h>
00123 #include <stdio.h>
00124 #include <stdlib.h>
00125 #include <unistd.h>
00126 #include "gis.h"
00127 
00128 #define G_ZLIB_COMPRESSED_NO (unsigned char)'0'
00129 #define G_ZLIB_COMPRESSED_YES (unsigned char)'1'
00130 
00131 static void
00132 _init_zstruct (z)
00133     z_stream *z;
00134 {
00135     /* The types are defined in zlib.h, we set to NULL so zlib uses
00136      * its default functions.
00137      */
00138     z->zalloc = (alloc_func)0;
00139     z->zfree  = (free_func)0;
00140     z->opaque = (voidpf)0;
00141 }
00142 
00143 int
00144 G_zlib_read (fd, rbytes, dst, nbytes)
00145     int fd, rbytes, nbytes;
00146     unsigned char *dst;
00147 {
00148     int bsize, nread, err;
00149     unsigned char *b;
00150 
00151     if (dst == NULL || nbytes < 0)
00152         return -2;
00153     
00154     bsize = rbytes;
00155 
00156     /* Our temporary input buffer for read */
00157     if (NULL == (b = (unsigned char *) 
00158                 G_calloc (bsize, sizeof(unsigned char))))
00159         return -1;
00160 
00161     /* Read from the file until we get our bsize or an error */
00162     nread = 0;
00163     do {
00164         err = read (fd, b + nread, bsize - nread);
00165         if (err >= 0)
00166             nread += err;
00167     } while (err > 0 && nread < bsize);
00168 
00169     /* If the bsize if less than rbytes and we didn't get an error.. */
00170     if (nread < rbytes && err > 0)
00171     {
00172         G_free (b);
00173         return -1;
00174     }
00175 
00176     /* Test if row is compressed */
00177     if (b[0] == G_ZLIB_COMPRESSED_NO)
00178     {
00179         /* Then just copy it to dst */
00180         for (err = 0; err < nread - 1 && err < nbytes; err++)
00181             dst[err] = b[err + 1];
00182         
00183         G_free (b);
00184         return (nread - 1);
00185     }
00186     else if (b[0] != G_ZLIB_COMPRESSED_YES)
00187     {
00188         /* We're not at the start of a row */
00189         G_free (b);
00190         return -1;
00191     }
00192     /* Okay it's a compressed row */
00193     
00194     /* Just call G_zlib_expand() with the buffer we read,
00195      * Account for first byte being a flag
00196      */
00197     err = G_zlib_expand (b+1, bsize-1, dst, nbytes);
00198 
00199     /* We're done with b */
00200     G_free (b);
00201     
00202     /* Return whatever G_zlib_expand() returned */
00203     return err;
00204     
00205 } /* G_zlib_read() */
00206 
00207 
00208 int
00209 G_zlib_write (fd, src, nbytes)
00210     int fd, nbytes;
00211     unsigned char *src;
00212 {
00213     int dst_sz, nwritten, err;
00214     unsigned char *dst, compressed;
00215     
00216     /* Catch errors */
00217     if (src == NULL || nbytes < 0)
00218         return -1;
00219     
00220     dst_sz = nbytes;
00221     if (NULL == (dst = (unsigned char *) 
00222                 G_calloc (dst_sz, sizeof (unsigned char))))
00223         return -1;
00224 
00225     /* Now just call G_zlib_compress() */
00226     err = G_zlib_compress (src, nbytes, dst, dst_sz);
00227 
00228     /* If compression succeeded write compressed row,
00229      * otherwise write uncompressed row. Compression will fail
00230      * if dst is too small (i.e. compressed data is larger)
00231      */
00232     if (err > 0 && err <= dst_sz)
00233     {
00234         dst_sz = err;
00235         /* Write the compression flag */
00236         compressed = G_ZLIB_COMPRESSED_YES;
00237         if (write (fd, &compressed, 1) != 1)
00238         {
00239             G_free (dst);
00240             return -1;
00241         }
00242         nwritten = 0;
00243         do
00244         {
00245             err = write (fd, dst + nwritten, dst_sz - nwritten);
00246             if (err >= 0)
00247                 nwritten += err;
00248         } while (err > 0 && nwritten < dst_sz);
00249         /* Account for extra byte */
00250         nwritten++;
00251     }
00252     else
00253     {
00254         /* Write compression flag */
00255         compressed = G_ZLIB_COMPRESSED_NO;
00256         if (write (fd, &compressed, 1) != 1)
00257         {
00258             G_free (dst);
00259             return -1;
00260         }
00261         nwritten = 0;
00262         do
00263         {
00264             err = write (fd, src + nwritten, nbytes - nwritten);
00265             if (err >= 0)
00266                 nwritten += err;
00267         } while (err > 0 && nwritten < nbytes);
00268         /* Account for extra byte */
00269         nwritten++;
00270     } /* if (err > 0) */
00271 
00272     /* Done with the dst buffer */
00273     G_free (dst);
00274     
00275     /* If we didn't write all the data return an error */
00276     if (err < 0)
00277         return -2;
00278 
00279     return nwritten;
00280 } /* G_zlib_write() */
00281 
00282 
00283 int
00284 G_zlib_write_noCompress (fd, src, nbytes)
00285     int fd, nbytes;
00286     unsigned char *src;
00287 {
00288     int err, nwritten;
00289     unsigned char compressed;
00290     
00291     /* Catch errors */
00292     if (src == NULL || nbytes < 0)
00293         return -1;
00294    
00295     /* Write the compression flag */
00296     compressed = G_ZLIB_COMPRESSED_NO;
00297     if (write (fd, &compressed, 1) != 1)
00298         return -1;
00299     
00300     /* Now write the data */
00301     nwritten = 0;
00302     do {
00303         err = write (fd, src + nwritten, nbytes - nwritten);
00304         if (err > 0)
00305             nwritten += err;
00306     } while (err > 0 && nwritten < nbytes);
00307 
00308     if (err < 0 || nwritten != nbytes)
00309         return -1;
00310 
00311     /* Account for extra compressed flag */
00312     nwritten++;
00313 
00314     /* That's all */
00315     return nwritten;
00316 
00317 } /* G_zlib_write_noCompress() */
00318 
00319 
00320 int
00321 G_zlib_compress (src, src_sz, dst, dst_sz)
00322     int src_sz, dst_sz;
00323     unsigned char *src, *dst;
00324 {
00325     int err, nbytes, buf_sz;
00326     unsigned char *buf;
00327     z_stream c_stream;
00328 
00329     /* Catch errors early */
00330     if (src == NULL || dst == NULL)
00331         return -1;
00332 
00333     /* Don't do anything if either of these are true */
00334     if (src_sz <= 0 || dst_sz <= 0)
00335         return 0;
00336 
00337     /* Output buffer has to be 1% + 12 bytes bigger for single pass deflate */
00338     buf_sz = (int) ( (double) dst_sz * 1.01 + (double) 12 );
00339     if (NULL == (buf = (unsigned char *)
00340                         G_calloc (buf_sz, sizeof(unsigned char))))
00341         return -1;
00342 
00343     /* Set-up for default zlib memory handling */
00344     _init_zstruct (&c_stream);
00345 
00346     /* Set-up the stream */
00347     c_stream.avail_in  = src_sz;
00348     c_stream.next_in   = src;
00349     c_stream.avail_out = buf_sz;
00350     c_stream.next_out  = buf;
00351 
00352     /* Initialize using default compression (usually 6) */
00353     err = deflateInit (&c_stream, Z_DEFAULT_COMPRESSION);
00354 
00355     /* If there was an error initializing, return -1 */
00356     if (err != Z_OK)
00357     {
00358         G_free (buf);
00359         return -1;
00360     }
00361     
00362     /* Do single pass compression */
00363     err = deflate (&c_stream, Z_FINISH);
00364     if (err != Z_STREAM_END)
00365     {
00366         switch (err)
00367         {
00368             case Z_OK:  /* Destination too small */
00369                 G_free (buf);
00370                 deflateEnd (&c_stream);
00371                 return -2;
00372                 break;
00373             default:    /* Give other error */
00374                 G_free (buf);
00375                 deflateEnd (&c_stream);
00376                 return -1;
00377                 break;
00378         }
00379     }
00380 
00381     /* avail_out is updated to bytes remaining in buf, so bytes of compressed
00382      * data is the original size minus that
00383      */
00384     nbytes = buf_sz - c_stream.avail_out;
00385     if (nbytes > dst_sz) /* Not enough room to copy output */
00386     {
00387         G_free (buf);
00388         return -2;
00389     }
00390     /* Copy the data from buf to dst */
00391     for (err = 0; err < nbytes; err++)
00392         dst[err] = buf[err];
00393     
00394     G_free (buf);
00395     deflateEnd (&c_stream);
00396 
00397     return nbytes;
00398 } /* G_zlib_compress() */
00399 
00400 int
00401 G_zlib_expand (src, src_sz, dst, dst_sz)
00402     int src_sz, dst_sz;
00403     unsigned char *src, *dst;
00404 {
00405     int err, nbytes;
00406     z_stream c_stream;
00407 
00408     /* Catch error condition */
00409     if (src == NULL || dst == NULL)
00410         return -2;
00411 
00412     /* Don't do anything if either of these are true */
00413     if (src_sz <= 0 || dst_sz <= 0)
00414         return 0;
00415 
00416     /* Set-up default zlib memory handling */
00417     _init_zstruct (&c_stream);
00418 
00419     /* Set-up I/O streams */
00420     c_stream.avail_in  = src_sz;
00421     c_stream.next_in   = src;
00422     c_stream.avail_out = dst_sz;
00423     c_stream.next_out  = dst;
00424 
00425     /* Call zlib initilization function */
00426     err = inflateInit (&c_stream);
00427 
00428     /* If not Z_OK return error -1 */
00429     if (err != Z_OK)
00430         return -1;
00431 
00432     /* Do single pass inflate */
00433     err = inflate (&c_stream, Z_FINISH);
00434 
00435      /* Number of bytes inflated to output stream is
00436      * original bytes available minus what avail_out now says
00437      */
00438     nbytes = dst_sz - c_stream.avail_out;
00439   
00440     /* Z_STREAM_END means all input was consumed, 
00441      * Z_OK means only some was processed (not enough room in dst)
00442      */
00443     if (!(err == Z_STREAM_END || err == Z_OK))
00444     {
00445         if (!(err == Z_BUF_ERROR && nbytes == dst_sz))
00446         {
00447             inflateEnd (&c_stream);
00448             return -1;
00449         } 
00450         /* Else, there was extra input, but requested output size was
00451          * decompressed successfully.
00452          */
00453     }
00454 
00455     inflateEnd (&c_stream);
00456 
00457     return nbytes;
00458 } /* G_zlib_expand() */
00459 
00460 #endif /* HAVE_ZLIB_H */
00461 
00462 
00463 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */

Generated on Wed Aug 23 17:49:22 2006 for GRASS by  doxygen 1.4.7