GRASS GIS 8 Programmer's Manual 8.2.1RC1(2022)-exported
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
78int
79G_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
90int
91G_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
169int
170G_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: alloc.c:149
#define NULL
Definition: ccmath.h:32
int G_zlib_compress_bound(int)
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204
char * dst
Definition: lz4.h:599
Definition: G.h:5
int compression_level
Definition: G.h:9
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220