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: */