GRASS GIS 8 Programmer's Manual  8.2.1(2023)-exported
cmprzstd.c
Go to the documentation of this file.
1 /*
2  ****************************************************************************
3  * -- GRASS Development Team --
4  *
5  * MODULE: GRASS gis library
6  * FILENAME: cmprzstd.c
7  * AUTHOR(S): Eric G. Miller <egm2@jps.net>
8  * Markus Metz
9  * PURPOSE: To provide an interface to ZSTD for compressing and
10  * decompressing data using ZSTD. It's primary use is in
11  * the storage and reading of GRASS floating point rasters.
12  *
13  * DATE CREATED: Dec 18 2017
14  * COPYRIGHT: (C) 2017 by the GRASS Development Team
15  *
16  * This program is free software under the GNU General Public
17  * License (version 2 or greater). Read the file COPYING that
18  * comes with GRASS for details.
19  *
20  *****************************************************************************/
21 
22 /********************************************************************
23  * int *
24  * G_zstd_compress (src, srz_sz, dst, dst_sz) *
25  * int src_sz, dst_sz; *
26  * unsigned char *src, *dst; *
27  * ---------------------------------------------------------------- *
28  * This function is a wrapper around the Zstd compression function. *
29  * It uses an all or nothing call. *
30  * If you need a continuous compression scheme, you'll have to code *
31  * your own. *
32  * In order to do a single pass compression, the input src must be *
33  * copied to a buffer larger than the data. This may cause *
34  * 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_zstd_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 zstd decompression *
50  * function. It uses a single pass call. If you need a continuous *
51  * 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 #ifdef HAVE_ZSTD_H
65 #include <zstd.h>
66 #endif
67 
68 #include <grass/gis.h>
69 #include <grass/glocale.h>
70 
71 
72 int
74 {
75  /* ZSTD has a fast version if destLen is large enough
76  * to hold a worst case result
77  */
78 #ifndef HAVE_ZSTD_H
79  G_fatal_error(_("GRASS needs to be compiled with ZSTD for ZSTD compression"));
80  return -1;
81 #else
82  return ZSTD_compressBound(src_sz);
83 #endif
84 }
85 
86 int
87 G_zstd_compress(unsigned char *src, int src_sz, unsigned char *dst,
88  int dst_sz)
89 {
90  int err, nbytes, buf_sz;
91  unsigned char *buf;
92 
93 #ifndef HAVE_ZSTD_H
94  G_fatal_error(_("GRASS needs to be compiled with ZSTD for ZSTD compression"));
95  return -1;
96 #else
97 
98  /* Catch errors early */
99  if (src == NULL || dst == NULL) {
100  if (src == NULL)
101  G_warning(_("No source buffer"));
102 
103  if (dst == NULL)
104  G_warning(_("No destination buffer"));
105  return -1;
106  }
107 
108  /* Don't do anything if either of these are true */
109  if (src_sz <= 0 || dst_sz <= 0) {
110  if (src_sz <= 0)
111  G_warning(_("Invalid source buffer size %d"), src_sz);
112  if (dst_sz <= 0)
113  G_warning(_("Invalid destination buffer size %d"), dst_sz);
114  return 0;
115  }
116 
117  /* Output buffer has to be larger for single pass compression */
118  buf = dst;
119  buf_sz = G_zstd_compress_bound(src_sz);
120  if (buf_sz > dst_sz) {
121  G_warning("G_zstd_compress(): programmer error, destination is too small");
122  if (NULL == (buf = (unsigned char *)
123  G_calloc(buf_sz, sizeof(unsigned char))))
124  return -1;
125  }
126  else
127  buf_sz = dst_sz;
128 
129  /* Do single pass compression */
130  err = ZSTD_compress((char *)buf, buf_sz, (char *)src, src_sz, 3);
131 
132  if (err <= 0 || ZSTD_isError(err)) {
133  G_warning(_("ZSTD compression error %d: %s"),
134  err, ZSTD_getErrorName(err));
135  if (buf != dst)
136  G_free(buf);
137  return -1;
138  }
139  if (err >= src_sz) {
140  /* compression not possible */
141  if (buf != dst)
142  G_free(buf);
143  return -2;
144  }
145 
146  /* bytes of compressed data is return value */
147  nbytes = err;
148 
149  if (buf != dst) {
150  /* Copy the data from buf to dst */
151  for (err = 0; err < nbytes; err++)
152  dst[err] = buf[err];
153 
154  G_free(buf);
155  }
156 
157  return nbytes;
158 #endif
159 }
160 
161 int
162 G_zstd_expand(unsigned char *src, int src_sz, unsigned char *dst,
163  int dst_sz)
164 {
165  int err, nbytes;
166 
167 #ifndef HAVE_ZSTD_H
168  G_fatal_error(_("GRASS needs to be compiled with ZSTD for ZSTD compression"));
169  return -1;
170 #else
171 
172  /* Catch error condition */
173  if (src == NULL || dst == NULL) {
174  if (src == NULL)
175  G_warning(_("No source buffer"));
176 
177  if (dst == NULL)
178  G_warning(_("No destination buffer"));
179  return -2;
180  }
181 
182  /* Don't do anything if either of these are true */
183  if (src_sz <= 0 || dst_sz <= 0) {
184  if (src_sz <= 0)
185  G_warning(_("Invalid source buffer size %d"), src_sz);
186  if (dst_sz <= 0)
187  G_warning(_("Invalid destination buffer size %d"), dst_sz);
188  return 0;
189  }
190 
191  /* Do single pass decompress */
192  err = ZSTD_decompress((char *)dst, dst_sz, (char *)src, src_sz);
193 
194  if (err <= 0 || ZSTD_isError(err)) {
195  G_warning(_("ZSTD compression error %d: %s"),
196  err, ZSTD_getErrorName(err));
197  return -1;
198  }
199 
200  /* Number of bytes inflated to output stream is return value */
201  nbytes = err;
202 
203  if (nbytes != dst_sz) {
204  /* TODO: it is not an error if destination is larger than needed */
205  G_warning(_("Got uncompressed size %d, expected %d"), (int)nbytes, dst_sz);
206  return -1;
207  }
208 
209  return nbytes;
210 #endif
211 }
212 
213 
214 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
G_zstd_compress
int G_zstd_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprzstd.c:87
G_fatal_error
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
err
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
G_zstd_expand
int G_zstd_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprzstd.c:162
G_free
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
G_zstd_compress_bound
int G_zstd_compress_bound(int src_sz)
Definition: cmprzstd.c:73
NULL
#define NULL
Definition: ccmath.h:32
dst
char * dst
Definition: lz4.h:599
G_warning
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204