GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
Loading...
Searching...
No Matches
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
76int 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
87int 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
165int 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: */
void G_free(void *buf)
Free allocated memory.
Definition alloc.c:150
#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:203
Definition G.h:5
int compression_level
Definition G.h:9
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)