GRASS GIS 7 Programmer's Manual  7.5.svn(2018)-r72892
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
cmprzlib.c
Go to the documentation of this file.
1 /*
2  ****************************************************************************
3  * -- GRASS Development Team --
4  *
5  * MODULE: GRASS gis library
6  * FILENAME: cmprzlib.c
7  * AUTHOR(S): Eric G. Miller <egm2@jps.net>
8  * Markus Metz
9  * PURPOSE: To provide an interface to libz for compressing and
10  * decompressing data using DEFLATE. It's primary use is in
11  * the storage and reading of GRASS floating point rasters.
12  * It replaces the patented LZW compression interface.
13  *
14  * ALGORITHM: http://www.gzip.org/zlib/feldspar.html
15  * DATE CREATED: Dec 17 2015
16  * COPYRIGHT: (C) 2015 by the GRASS Development Team
17  *
18  * This program is free software under the GNU General Public
19  * License (version 2 or greater). Read the file COPYING that
20  * comes with GRASS for details.
21  *
22  *****************************************************************************/
23 
24 /********************************************************************
25  * int *
26  * G_zlib_compress (src, srz_sz, dst, dst_sz) *
27  * int src_sz, dst_sz; *
28  * unsigned char *src, *dst; *
29  * ---------------------------------------------------------------- *
30  * This function is a wrapper around the zlib deflate() function. *
31  * It uses an all or nothing call to deflate(). If you need a *
32  * continuous compression scheme, you'll have to code your own. *
33  * In order to do a single pass compression, the input src must be *
34  * copied to a buffer 1% + 12 bytes larger than the data. This may *
35  * cause performance degradation. *
36  * *
37  * The function either returns the number of bytes of compressed *
38  * data in dst, or an error code. *
39  * *
40  * Errors include: *
41  * -1 -- Compression failed. *
42  * -2 -- dst is too small. *
43  * *
44  * ================================================================ *
45  * int *
46  * G_zlib_expand (src, src_sz, dst, dst_sz) *
47  * int src_sz, dst_sz; *
48  * unsigned char *src, *dst; *
49  * ---------------------------------------------------------------- *
50  * This function is a wrapper around the zlib inflate() function. *
51  * It uses a single pass call to inflate(). If you need a contin- *
52  * uous expansion scheme, you'll have to code your own. *
53  * *
54  * The function returns the number of bytes expanded into 'dst' or *
55  * and error code. *
56  * *
57  * Errors include: *
58  * -1 -- Expansion failed. *
59  * *
60  ********************************************************************
61  */
62 
63 #include <grass/config.h>
64 
65 #ifndef HAVE_ZLIB_H
66 
67 #error "GRASS requires libz to compile"
68 
69 #else
70 
71 #include <zlib.h>
72 #include <grass/gis.h>
73 #include <grass/glocale.h>
74 
75 #include "G.h"
76 
77 
78 int
79 G_zlib_compress_bound(int src_sz)
80 {
81  /* from zlib.h:
82  * "when using compress or compress2,
83  * destLen must be at least the value returned by
84  * compressBound(sourceLen)"
85  * no explanation for the "must be"
86  */
87  return compressBound(src_sz);
88 }
89 
90 int
91 G_zlib_compress(unsigned char *src, int src_sz, unsigned char *dst,
92  int dst_sz)
93 {
94  uLong err, nbytes, buf_sz;
95  unsigned char *buf;
96 
97  /* Catch errors early */
98  if (src == NULL || dst == NULL) {
99  if (src == NULL)
100  G_warning(_("No source buffer"));
101 
102  if (dst == NULL)
103  G_warning(_("No destination buffer"));
104  return -1;
105  }
106 
107  /* Don't do anything if either of these are true */
108  if (src_sz <= 0 || dst_sz <= 0) {
109  if (src_sz <= 0)
110  G_warning(_("Invalid source buffer size %d"), src_sz);
111  if (dst_sz <= 0)
112  G_warning(_("Invalid destination buffer size %d"), dst_sz);
113  return 0;
114  }
115 
116  /* Output buffer has to be 1% + 12 bytes bigger for single pass deflate */
117  /* buf_sz = (int)((double)dst_sz * 1.01 + (double)12); */
118 
119  /* Output buffer should be large enough for single pass compression */
120  buf = dst;
121  buf_sz = G_zlib_compress_bound(src_sz);
122  if (buf_sz > dst_sz) {
123  G_warning("G_zlib_compress(): programmer error, destination is too small");
124  if (NULL == (buf = (unsigned char *)
125  G_calloc(buf_sz, sizeof(unsigned char))))
126  return -1;
127  }
128  else
129  buf_sz = dst_sz;
130 
131  /* Valid zlib compression levels -1 - 9 */
132  /* zlib default: Z_DEFAULT_COMPRESSION = -1, equivalent to 6
133  * as used here, 1 gives the best compromise between speed and compression */
134 
135  /* Do single pass compression */
136  nbytes = buf_sz;
137  err = compress2((Bytef *)buf, &nbytes, /* destination */
138  (const Bytef *)src, src_sz, /* source */
139  G__.compression_level); /* level */
140 
141  if (err != Z_OK) {
142  G_warning(_("ZLIB compression error %d: %s"),
143  (int)err, zError(err));
144  if (buf != dst)
145  G_free(buf);
146  return -1;
147  }
148 
149  /* updated buf_sz is bytes of compressed data */
150  if (nbytes >= src_sz) {
151  /* compression not possible */
152  if (buf != dst)
153  G_free(buf);
154  return -2;
155  }
156 
157  if (buf != dst) {
158  /* Copy the data from buf to dst */
159  for (err = 0; err < nbytes; err++)
160  dst[err] = buf[err];
161 
162  G_free(buf);
163  }
164 
165  return nbytes;
166 } /* G_zlib_compress() */
167 
168 
169 int
170 G_zlib_expand(unsigned char *src, int src_sz, unsigned char *dst,
171  int dst_sz)
172 {
173  int err;
174  uLong ss, nbytes;
175 
176  /* Catch error condition */
177  if (src == NULL || dst == NULL) {
178  if (src == NULL)
179  G_warning(_("No source buffer"));
180 
181  if (dst == NULL)
182  G_warning(_("No destination buffer"));
183  return -2;
184  }
185 
186  /* Don't do anything if either of these are true */
187  if (src_sz <= 0 || dst_sz <= 0) {
188  if (src_sz <= 0)
189  G_warning(_("Invalid source buffer size %d"), src_sz);
190  if (dst_sz <= 0)
191  G_warning(_("Invalid destination buffer size %d"), dst_sz);
192  return 0;
193  }
194 
195  ss = src_sz;
196 
197  /* Do single pass decompression */
198  nbytes = dst_sz;
199  err = uncompress((Bytef *)dst, &nbytes, /* destination */
200  (const Bytef *)src, ss); /* source */
201 
202  /* If not Z_OK return error -1 */
203  if (err != Z_OK) {
204  G_warning(_("ZLIB decompression error %d: %s"),
205  err, zError(err));
206  return -1;
207  }
208 
209  /* Number of bytes inflated to output stream is
210  * updated buffer size
211  */
212 
213  if (nbytes != dst_sz) {
214  /* TODO: it is not an error if destination is larger than needed */
215  G_warning(_("Got uncompressed size %d, expected %d"), (int)nbytes, dst_sz);
216  return -1;
217  }
218 
219  return nbytes;
220 } /* G_zlib_expand() */
221 
222 
223 #endif /* HAVE_ZLIB_H */
224 
225 
226 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
void G_free(void *buf)
Free allocated memory.
Definition: gis/alloc.c:149
int G_zlib_compress_bound(int)
char * dst
Definition: lz4.h:599
#define NULL
Definition: ccmath.h:32
int compression_level
Definition: G.h:9
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
Definition: G.h:4
#define _(str)
Definition: glocale.h:13
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204