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