GRASS Programmer's Manual  6.5.svn(2014)-r66266
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
flate.c
Go to the documentation of this file.
1 /*
2  ****************************************************************************
3  * -- GRASS Development Team --
4  *
5  * MODULE: GRASS gis library
6  * FILENAME: flate.c
7  * AUTHOR(S): Eric G. Miller <egm2@jps.net>
8  * PURPOSE: To provide an interface to libz for compressing and
9  * decompressing data using DEFLATE. It's primary use is in
10  * the storage and reading of GRASS floating point rasters.
11  * It replaces the patented LZW compression interface.
12  *
13  * ALGORITHM: http://www.gzip.org/zlib/feldspar.html
14  * DATE CREATED: Nov 19 2000
15  * COPYRIGHT: (C) 2000 by the GRASS Development Team
16  *
17  * This program is free software under the GNU General Public
18  * License (version 2 or greater). Read the file COPYING that
19  * comes with GRASS for details.
20  *
21  *****************************************************************************/
22 
23 /********************************************************************
24  * int *
25  * G_zlib_read (fd, rbytes, dst, nbytes) *
26  * int fd, rbytes, nbytes; *
27  * unsigned char *dst; *
28  * ---------------------------------------------------------------- *
29  * This is the basic function for reading a compressed chunk of a *
30  * data file. The file descriptor should be in the proper location *
31  * and the 'dst' array should have enough space for the data. *
32  * 'nbytes' is the size of 'dst'. The 'rbytes' parameter is the *
33  * number of bytes to read (knowable from the offsets index). For *
34  * best results, 'nbytes' should be the exact amount of space *
35  * needed for the expansion. Too large a value of nbytes may cause *
36  * more data to be expanded than is desired. *
37  * Returns: The number of bytes decompressed into dst, or an error. *
38  * *
39  * Errors include: *
40  * -1 -- Error Reading or Decompressing data. *
41  * -2 -- Not enough space in dst. You must make dst larger *
42  * and then call the function again (remembering to *
43  * reset the file descriptor to it's proper location. *
44  * *
45  * ================================================================ *
46  * int *
47  * G_zlib_write (fd, src, nbytes) *
48  * int fd, nbytes; *
49  * unsigned char *src; *
50  * ---------------------------------------------------------------- *
51  * This is the basic function for writing and compressing a data *
52  * chunk to a file. The file descriptor should be in the correct *
53  * location prior to this call. The function will compress 'nbytes' *
54  * of 'src' and write it to the file 'fd'. Returns the number of *
55  * bytes written or an error code: *
56  * *
57  * Errors include: *
58  * -1 -- Compression Failed. *
59  * -2 -- Unable to write to file. *
60  * *
61  * ================================================================ *
62  * int *
63  * G_zlib_write_noCompress (fd, src, nbytes) *
64  * int fd, nbytes; *
65  * unsigned char *src; *
66  * ---------------------------------------------------------------- *
67  * Works similar to G_zlib_write() except no attempt at compression *
68  * is made. This is quicker, but may result in larger files. *
69  * Returns the number of bytes written, or -1 for an error. It will *
70  * return an error if it fails to write nbytes. Otherwise, the *
71  * return value will always be nbytes + 1 (for compression flag). *
72  * *
73  * ================================================================ *
74  * int *
75  * G_zlib_compress (src, srz_sz, dst, dst_sz) *
76  * int src_sz, dst_sz; *
77  * unsigned char *src, *dst; *
78  * ---------------------------------------------------------------- *
79  * This function is a wrapper around the zlib deflate() function. *
80  * It uses an all or nothing call to deflate(). If you need a *
81  * continuous compression scheme, you'll have to code your own. *
82  * In order to do a single pass compression, the input src must be *
83  * copied to a buffer 1% + 12 bytes larger than the data. This may *
84  * cause performance degradation. *
85  * *
86  * The function either returns the number of bytes of compressed *
87  * data in dst, or an error code. *
88  * *
89  * Errors include: *
90  * -1 -- Compression failed. *
91  * -2 -- dst is too small. *
92  * *
93  * ================================================================ *
94  * int *
95  * G_zlib_expand (src, src_sz, dst, dst_sz) *
96  * int src_sz, dst_sz; *
97  * unsigned char *src, *dst; *
98  * ---------------------------------------------------------------- *
99  * This function is a wrapper around the zlib inflate() function. *
100  * It uses a single pass call to inflate(). If you need a contin- *
101  * uous expansion scheme, you'll have to code your own. *
102  * *
103  * The function returns the number of bytes expanded into 'dst' or *
104  * and error code. *
105  * *
106  * Errors include: *
107  * -1 -- Expansion failed. *
108  * *
109  ********************************************************************
110  */
111 
112 #include <grass/config.h>
113 
114 #ifndef HAVE_ZLIB_H
115 
116 #error "GRASS requires libz to compile"
117 
118 #else
119 
120 #include <zlib.h>
121 #include <stdio.h>
122 #include <stdlib.h>
123 #include <unistd.h>
124 #include <grass/gis.h>
125 
126 #define G_ZLIB_COMPRESSED_NO (unsigned char)'0'
127 #define G_ZLIB_COMPRESSED_YES (unsigned char)'1'
128 
129 static void _init_zstruct(z_stream * z)
130 {
131  /* The types are defined in zlib.h, we set to NULL so zlib uses
132  * its default functions.
133  */
134  z->zalloc = (alloc_func) 0;
135  z->zfree = (free_func) 0;
136  z->opaque = (voidpf) 0;
137 }
138 
139 int G_zlib_read(int fd, int rbytes, unsigned char *dst, int nbytes)
140 {
141  int bsize, nread, err;
142  unsigned char *b;
143 
144  if (dst == NULL || nbytes < 0)
145  return -2;
146 
147  bsize = rbytes;
148 
149  /* Our temporary input buffer for read */
150  if (NULL == (b = (unsigned char *)
151  G_calloc(bsize, sizeof(unsigned char))))
152  return -1;
153 
154  /* Read from the file until we get our bsize or an error */
155  nread = 0;
156  do {
157  err = read(fd, b + nread, bsize - nread);
158  if (err >= 0)
159  nread += err;
160  } while (err > 0 && nread < bsize);
161 
162  /* If the bsize if less than rbytes and we didn't get an error.. */
163  if (nread < rbytes && err > 0) {
164  G_free(b);
165  return -1;
166  }
167 
168  /* Test if row is compressed */
169  if (b[0] == G_ZLIB_COMPRESSED_NO) {
170  /* Then just copy it to dst */
171  for (err = 0; err < nread - 1 && err < nbytes; err++)
172  dst[err] = b[err + 1];
173 
174  G_free(b);
175  return (nread - 1);
176  }
177  else if (b[0] != G_ZLIB_COMPRESSED_YES) {
178  /* We're not at the start of a row */
179  G_free(b);
180  return -1;
181  }
182  /* Okay it's a compressed row */
183 
184  /* Just call G_zlib_expand() with the buffer we read,
185  * Account for first byte being a flag
186  */
187  err = G_zlib_expand(b + 1, bsize - 1, dst, nbytes);
188 
189  /* We're done with b */
190  G_free(b);
191 
192  /* Return whatever G_zlib_expand() returned */
193  return err;
194 
195 } /* G_zlib_read() */
196 
197 
198 int G_zlib_write(int fd, const unsigned char *src, int nbytes)
199 {
200  int dst_sz, nwritten, err;
201  unsigned char *dst, compressed;
202 
203  /* Catch errors */
204  if (src == NULL || nbytes < 0)
205  return -1;
206 
207  dst_sz = nbytes;
208  if (NULL == (dst = (unsigned char *)
209  G_calloc(dst_sz, sizeof(unsigned char))))
210  return -1;
211 
212  /* Now just call G_zlib_compress() */
213  err = G_zlib_compress(src, nbytes, dst, dst_sz);
214 
215  /* If compression succeeded write compressed row,
216  * otherwise write uncompressed row. Compression will fail
217  * if dst is too small (i.e. compressed data is larger)
218  */
219  if (err > 0 && err <= dst_sz) {
220  dst_sz = err;
221  /* Write the compression flag */
222  compressed = G_ZLIB_COMPRESSED_YES;
223  if (write(fd, &compressed, 1) != 1) {
224  G_free(dst);
225  return -1;
226  }
227  nwritten = 0;
228  do {
229  err = write(fd, dst + nwritten, dst_sz - nwritten);
230  if (err >= 0)
231  nwritten += err;
232  } while (err > 0 && nwritten < dst_sz);
233  /* Account for extra byte */
234  nwritten++;
235  }
236  else {
237  /* Write compression flag */
238  compressed = G_ZLIB_COMPRESSED_NO;
239  if (write(fd, &compressed, 1) != 1) {
240  G_free(dst);
241  return -1;
242  }
243  nwritten = 0;
244  do {
245  err = write(fd, src + nwritten, nbytes - nwritten);
246  if (err >= 0)
247  nwritten += err;
248  } while (err > 0 && nwritten < nbytes);
249  /* Account for extra byte */
250  nwritten++;
251  } /* if (err > 0) */
252 
253  /* Done with the dst buffer */
254  G_free(dst);
255 
256  /* If we didn't write all the data return an error */
257  if (err < 0)
258  return -2;
259 
260  return nwritten;
261 } /* G_zlib_write() */
262 
263 
264 int G_zlib_write_noCompress(int fd, const unsigned char *src, int nbytes)
265 {
266  int err, nwritten;
267  unsigned char compressed;
268 
269  /* Catch errors */
270  if (src == NULL || nbytes < 0)
271  return -1;
272 
273  /* Write the compression flag */
274  compressed = G_ZLIB_COMPRESSED_NO;
275  if (write(fd, &compressed, 1) != 1)
276  return -1;
277 
278  /* Now write the data */
279  nwritten = 0;
280  do {
281  err = write(fd, src + nwritten, nbytes - nwritten);
282  if (err > 0)
283  nwritten += err;
284  } while (err > 0 && nwritten < nbytes);
285 
286  if (err < 0 || nwritten != nbytes)
287  return -1;
288 
289  /* Account for extra compressed flag */
290  nwritten++;
291 
292  /* That's all */
293  return nwritten;
294 
295 } /* G_zlib_write_noCompress() */
296 
297 
298 int
299 G_zlib_compress(const unsigned char *src, int src_sz, unsigned char *dst,
300  int dst_sz)
301 {
302  int err, nbytes, buf_sz;
303  unsigned char *buf;
304  z_stream c_stream;
305 
306  /* Catch errors early */
307  if (src == NULL || dst == NULL)
308  return -1;
309 
310  /* Don't do anything if either of these are true */
311  if (src_sz <= 0 || dst_sz <= 0)
312  return 0;
313 
314  /* Output buffer has to be 1% + 12 bytes bigger for single pass deflate */
315  buf_sz = (int)((double)dst_sz * 1.01 + (double)12);
316  if (NULL == (buf = (unsigned char *)
317  G_calloc(buf_sz, sizeof(unsigned char))))
318  return -1;
319 
320  /* Set-up for default zlib memory handling */
321  _init_zstruct(&c_stream);
322 
323  /* Set-up the stream */
324  c_stream.avail_in = src_sz;
325  c_stream.next_in = (char *)src;
326  c_stream.avail_out = buf_sz;
327  c_stream.next_out = buf;
328 
329  /* Initialize using default compression (usually 6) */
330  err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION);
331 
332  /* If there was an error initializing, return -1 */
333  if (err != Z_OK) {
334  G_free(buf);
335  return -1;
336  }
337 
338  /* Do single pass compression */
339  err = deflate(&c_stream, Z_FINISH);
340  if (err != Z_STREAM_END) {
341  switch (err) {
342  case Z_OK: /* Destination too small */
343  G_free(buf);
344  deflateEnd(&c_stream);
345  return -2;
346  break;
347  default: /* Give other error */
348  G_free(buf);
349  deflateEnd(&c_stream);
350  return -1;
351  break;
352  }
353  }
354 
355  /* avail_out is updated to bytes remaining in buf, so bytes of compressed
356  * data is the original size minus that
357  */
358  nbytes = buf_sz - c_stream.avail_out;
359  if (nbytes > dst_sz) { /* Not enough room to copy output */
360  G_free(buf);
361  return -2;
362  }
363  /* Copy the data from buf to dst */
364  for (err = 0; err < nbytes; err++)
365  dst[err] = buf[err];
366 
367  G_free(buf);
368  deflateEnd(&c_stream);
369 
370  return nbytes;
371 } /* G_zlib_compress() */
372 
373 int
374 G_zlib_expand(const unsigned char *src, int src_sz, unsigned char *dst,
375  int dst_sz)
376 {
377  int err, nbytes;
378  z_stream c_stream;
379 
380  /* Catch error condition */
381  if (src == NULL || dst == NULL)
382  return -2;
383 
384  /* Don't do anything if either of these are true */
385  if (src_sz <= 0 || dst_sz <= 0)
386  return 0;
387 
388  /* Set-up default zlib memory handling */
389  _init_zstruct(&c_stream);
390 
391  /* Set-up I/O streams */
392  c_stream.avail_in = src_sz;
393  c_stream.next_in = (char *)src;
394  c_stream.avail_out = dst_sz;
395  c_stream.next_out = dst;
396 
397  /* Call zlib initilization function */
398  err = inflateInit(&c_stream);
399 
400  /* If not Z_OK return error -1 */
401  if (err != Z_OK)
402  return -1;
403 
404  /* Do single pass inflate */
405  err = inflate(&c_stream, Z_FINISH);
406 
407  /* Number of bytes inflated to output stream is
408  * original bytes available minus what avail_out now says
409  */
410  nbytes = dst_sz - c_stream.avail_out;
411 
412  /* Z_STREAM_END means all input was consumed,
413  * Z_OK means only some was processed (not enough room in dst)
414  */
415  if (!(err == Z_STREAM_END || err == Z_OK)) {
416  if (!(err == Z_BUF_ERROR && nbytes == dst_sz)) {
417  inflateEnd(&c_stream);
418  return -1;
419  }
420  /* Else, there was extra input, but requested output size was
421  * decompressed successfully.
422  */
423  }
424 
425  inflateEnd(&c_stream);
426 
427  return nbytes;
428 } /* G_zlib_expand() */
429 
430 #endif /* HAVE_ZLIB_H */
431 
432 
433 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:142
float b
Definition: named_colr.c:8
FILE * fd
Definition: g3dcolor.c:368
const char * err
Definition: g3dcolor.c:50
int
Definition: g3dcolor.c:48
char buf[GNAME_MAX+sizeof(G3D_DIRECTORY)+2]
Definition: g3drange.c:62
return NULL
Definition: dbfopen.c:1394