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