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