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