flate.c

Go to the documentation of this file.
00001 /*
00002  * $Id: flate.c,v 2.2 2006/02/09 03:08:56 glynn 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 <grass/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 <grass/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_stream *z)
00133 
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  (int fd, int rbytes, unsigned char *dst, int nbytes)
00145 
00146 {
00147     int bsize, nread, err;
00148     unsigned char *b;
00149 
00150     if (dst == NULL || nbytes < 0)
00151         return -2;
00152     
00153     bsize = rbytes;
00154 
00155     /* Our temporary input buffer for read */
00156     if (NULL == (b = (unsigned char *) 
00157                 G_calloc (bsize, sizeof(unsigned char))))
00158         return -1;
00159 
00160     /* Read from the file until we get our bsize or an error */
00161     nread = 0;
00162     do {
00163         err = read (fd, b + nread, bsize - nread);
00164         if (err >= 0)
00165             nread += err;
00166     } while (err > 0 && nread < bsize);
00167 
00168     /* If the bsize if less than rbytes and we didn't get an error.. */
00169     if (nread < rbytes && err > 0)
00170     {
00171         G_free (b);
00172         return -1;
00173     }
00174 
00175     /* Test if row is compressed */
00176     if (b[0] == G_ZLIB_COMPRESSED_NO)
00177     {
00178         /* Then just copy it to dst */
00179         for (err = 0; err < nread - 1 && err < nbytes; err++)
00180             dst[err] = b[err + 1];
00181         
00182         G_free (b);
00183         return (nread - 1);
00184     }
00185     else if (b[0] != G_ZLIB_COMPRESSED_YES)
00186     {
00187         /* We're not at the start of a row */
00188         G_free (b);
00189         return -1;
00190     }
00191     /* Okay it's a compressed row */
00192     
00193     /* Just call G_zlib_expand() with the buffer we read,
00194      * Account for first byte being a flag
00195      */
00196     err = G_zlib_expand (b+1, bsize-1, dst, nbytes);
00197 
00198     /* We're done with b */
00199     G_free (b);
00200     
00201     /* Return whatever G_zlib_expand() returned */
00202     return err;
00203     
00204 } /* G_zlib_read() */
00205 
00206 
00207 int
00208 G_zlib_write  (int fd, unsigned char *src, int nbytes)
00209 
00210 {
00211     int dst_sz, nwritten, err;
00212     unsigned char *dst, compressed;
00213     
00214     /* Catch errors */
00215     if (src == NULL || nbytes < 0)
00216         return -1;
00217     
00218     dst_sz = nbytes;
00219     if (NULL == (dst = (unsigned char *) 
00220                 G_calloc (dst_sz, sizeof (unsigned char))))
00221         return -1;
00222 
00223     /* Now just call G_zlib_compress() */
00224     err = G_zlib_compress (src, nbytes, dst, dst_sz);
00225 
00226     /* If compression succeeded write compressed row,
00227      * otherwise write uncompressed row. Compression will fail
00228      * if dst is too small (i.e. compressed data is larger)
00229      */
00230     if (err > 0 && err <= dst_sz)
00231     {
00232         dst_sz = err;
00233         /* Write the compression flag */
00234         compressed = G_ZLIB_COMPRESSED_YES;
00235         if (write (fd, &compressed, 1) != 1)
00236         {
00237             G_free (dst);
00238             return -1;
00239         }
00240         nwritten = 0;
00241         do
00242         {
00243             err = write (fd, dst + nwritten, dst_sz - nwritten);
00244             if (err >= 0)
00245                 nwritten += err;
00246         } while (err > 0 && nwritten < dst_sz);
00247         /* Account for extra byte */
00248         nwritten++;
00249     }
00250     else
00251     {
00252         /* Write compression flag */
00253         compressed = G_ZLIB_COMPRESSED_NO;
00254         if (write (fd, &compressed, 1) != 1)
00255         {
00256             G_free (dst);
00257             return -1;
00258         }
00259         nwritten = 0;
00260         do
00261         {
00262             err = write (fd, src + nwritten, nbytes - nwritten);
00263             if (err >= 0)
00264                 nwritten += err;
00265         } while (err > 0 && nwritten < nbytes);
00266         /* Account for extra byte */
00267         nwritten++;
00268     } /* if (err > 0) */
00269 
00270     /* Done with the dst buffer */
00271     G_free (dst);
00272     
00273     /* If we didn't write all the data return an error */
00274     if (err < 0)
00275         return -2;
00276 
00277     return nwritten;
00278 } /* G_zlib_write() */
00279 
00280 
00281 int
00282 G_zlib_write_noCompress  (int fd, unsigned char *src, int nbytes)
00283 
00284 {
00285     int err, nwritten;
00286     unsigned char compressed;
00287     
00288     /* Catch errors */
00289     if (src == NULL || nbytes < 0)
00290         return -1;
00291    
00292     /* Write the compression flag */
00293     compressed = G_ZLIB_COMPRESSED_NO;
00294     if (write (fd, &compressed, 1) != 1)
00295         return -1;
00296     
00297     /* Now write the data */
00298     nwritten = 0;
00299     do {
00300         err = write (fd, src + nwritten, nbytes - nwritten);
00301         if (err > 0)
00302             nwritten += err;
00303     } while (err > 0 && nwritten < nbytes);
00304 
00305     if (err < 0 || nwritten != nbytes)
00306         return -1;
00307 
00308     /* Account for extra compressed flag */
00309     nwritten++;
00310 
00311     /* That's all */
00312     return nwritten;
00313 
00314 } /* G_zlib_write_noCompress() */
00315 
00316 
00317 int
00318 G_zlib_compress  (unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
00319 
00320 {
00321     int err, nbytes, buf_sz;
00322     unsigned char *buf;
00323     z_stream c_stream;
00324 
00325     /* Catch errors early */
00326     if (src == NULL || dst == NULL)
00327         return -1;
00328 
00329     /* Don't do anything if either of these are true */
00330     if (src_sz <= 0 || dst_sz <= 0)
00331         return 0;
00332 
00333     /* Output buffer has to be 1% + 12 bytes bigger for single pass deflate */
00334     buf_sz = (int) ( (double) dst_sz * 1.01 + (double) 12 );
00335     if (NULL == (buf = (unsigned char *)
00336                         G_calloc (buf_sz, sizeof(unsigned char))))
00337         return -1;
00338 
00339     /* Set-up for default zlib memory handling */
00340     _init_zstruct (&c_stream);
00341 
00342     /* Set-up the stream */
00343     c_stream.avail_in  = src_sz;
00344     c_stream.next_in   = src;
00345     c_stream.avail_out = buf_sz;
00346     c_stream.next_out  = buf;
00347 
00348     /* Initialize using default compression (usually 6) */
00349     err = deflateInit (&c_stream, Z_DEFAULT_COMPRESSION);
00350 
00351     /* If there was an error initializing, return -1 */
00352     if (err != Z_OK)
00353     {
00354         G_free (buf);
00355         return -1;
00356     }
00357     
00358     /* Do single pass compression */
00359     err = deflate (&c_stream, Z_FINISH);
00360     if (err != Z_STREAM_END)
00361     {
00362         switch (err)
00363         {
00364             case Z_OK:  /* Destination too small */
00365                 G_free (buf);
00366                 deflateEnd (&c_stream);
00367                 return -2;
00368                 break;
00369             default:    /* Give other error */
00370                 G_free (buf);
00371                 deflateEnd (&c_stream);
00372                 return -1;
00373                 break;
00374         }
00375     }
00376 
00377     /* avail_out is updated to bytes remaining in buf, so bytes of compressed
00378      * data is the original size minus that
00379      */
00380     nbytes = buf_sz - c_stream.avail_out;
00381     if (nbytes > dst_sz) /* Not enough room to copy output */
00382     {
00383         G_free (buf);
00384         return -2;
00385     }
00386     /* Copy the data from buf to dst */
00387     for (err = 0; err < nbytes; err++)
00388         dst[err] = buf[err];
00389     
00390     G_free (buf);
00391     deflateEnd (&c_stream);
00392 
00393     return nbytes;
00394 } /* G_zlib_compress() */
00395 
00396 int
00397 G_zlib_expand  (unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
00398 
00399 {
00400     int err, nbytes;
00401     z_stream c_stream;
00402 
00403     /* Catch error condition */
00404     if (src == NULL || dst == NULL)
00405         return -2;
00406 
00407     /* Don't do anything if either of these are true */
00408     if (src_sz <= 0 || dst_sz <= 0)
00409         return 0;
00410 
00411     /* Set-up default zlib memory handling */
00412     _init_zstruct (&c_stream);
00413 
00414     /* Set-up I/O streams */
00415     c_stream.avail_in  = src_sz;
00416     c_stream.next_in   = src;
00417     c_stream.avail_out = dst_sz;
00418     c_stream.next_out  = dst;
00419 
00420     /* Call zlib initilization function */
00421     err = inflateInit (&c_stream);
00422 
00423     /* If not Z_OK return error -1 */
00424     if (err != Z_OK)
00425         return -1;
00426 
00427     /* Do single pass inflate */
00428     err = inflate (&c_stream, Z_FINISH);
00429 
00430      /* Number of bytes inflated to output stream is
00431      * original bytes available minus what avail_out now says
00432      */
00433     nbytes = dst_sz - c_stream.avail_out;
00434   
00435     /* Z_STREAM_END means all input was consumed, 
00436      * Z_OK means only some was processed (not enough room in dst)
00437      */
00438     if (!(err == Z_STREAM_END || err == Z_OK))
00439     {
00440         if (!(err == Z_BUF_ERROR && nbytes == dst_sz))
00441         {
00442             inflateEnd (&c_stream);
00443             return -1;
00444         } 
00445         /* Else, there was extra input, but requested output size was
00446          * decompressed successfully.
00447          */
00448     }
00449 
00450     inflateEnd (&c_stream);
00451 
00452     return nbytes;
00453 } /* G_zlib_expand() */
00454 
00455 #endif /* HAVE_ZLIB_H */
00456 
00457 
00458 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */

Generated on Fri Nov 21 11:02:17 2008 for GRASS by  doxygen 1.5.1