GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
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  * ALGORITHM: http://www.zstd.net
14  * DATE CREATED: Dec 18 2017
15  * COPYRIGHT: (C) 2017 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_zstd_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 Zstd compression function. *
30  * It uses an all or nothing call. *
31  * If you need a continuous compression scheme, you'll have to code *
32  * your own. *
33  * In order to do a single pass compression, the input src must be *
34  * copied to a buffer larger than the data. This may cause *
35  * 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_zstd_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 zstd decompression *
51  * function. It uses a single pass call. If you need a continuous *
52  * 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 #ifdef HAVE_ZSTD_H
66 #include <zstd.h>
67 #endif
68 
69 #include <grass/gis.h>
70 #include <grass/glocale.h>
71 
72 
73 int
75 {
76  /* ZSTD has a fast version if destLen is large enough
77  * to hold a worst case result
78  */
79 #ifndef HAVE_ZSTD_H
80  G_fatal_error(_("GRASS needs to be compiled with ZSTD for ZSTD compression"));
81  return -1;
82 #else
83  return ZSTD_compressBound(src_sz);
84 #endif
85 }
86 
87 int
88 G_zstd_compress(unsigned char *src, int src_sz, unsigned char *dst,
89  int dst_sz)
90 {
91  int err, nbytes, buf_sz;
92  unsigned char *buf;
93 
94 #ifndef HAVE_ZSTD_H
95  G_fatal_error(_("GRASS needs to be compiled with ZSTD for ZSTD compression"));
96  return -1;
97 #else
98 
99  /* Catch errors early */
100  if (src == NULL || dst == NULL) {
101  if (src == NULL)
102  G_warning(_("No source buffer"));
103 
104  if (dst == NULL)
105  G_warning(_("No destination buffer"));
106  return -1;
107  }
108 
109  /* Don't do anything if either of these are true */
110  if (src_sz <= 0 || dst_sz <= 0) {
111  if (src_sz <= 0)
112  G_warning(_("Invalid source buffer size %d"), src_sz);
113  if (dst_sz <= 0)
114  G_warning(_("Invalid destination buffer size %d"), dst_sz);
115  return 0;
116  }
117 
118  /* Output buffer has to be larger for single pass compression */
119  buf = dst;
120  buf_sz = G_zstd_compress_bound(src_sz);
121  if (buf_sz > dst_sz) {
122  G_warning("G_zstd_compress(): programmer error, destination is too small");
123  if (NULL == (buf = (unsigned char *)
124  G_calloc(buf_sz, sizeof(unsigned char))))
125  return -1;
126  }
127  else
128  buf_sz = dst_sz;
129 
130  /* Do single pass compression */
131  err = ZSTD_compress((char *)buf, buf_sz, (char *)src, src_sz, 3);
132 
133  if (err <= 0 || ZSTD_isError(err)) {
134  G_warning(_("ZSTD compression error %d: %s"),
135  err, ZSTD_getErrorName(err));
136  if (buf != dst)
137  G_free(buf);
138  return -1;
139  }
140  if (err >= src_sz) {
141  /* compression not possible */
142  if (buf != dst)
143  G_free(buf);
144  return -2;
145  }
146 
147  /* bytes of compressed data is return value */
148  nbytes = err;
149 
150  if (buf != dst) {
151  /* Copy the data from buf to dst */
152  for (err = 0; err < nbytes; err++)
153  dst[err] = buf[err];
154 
155  G_free(buf);
156  }
157 
158  return nbytes;
159 #endif
160 }
161 
162 int
163 G_zstd_expand(unsigned char *src, int src_sz, unsigned char *dst,
164  int dst_sz)
165 {
166  int err, nbytes;
167 
168 #ifndef HAVE_ZSTD_H
169  G_fatal_error(_("GRASS needs to be compiled with ZSTD for ZSTD compression"));
170  return -1;
171 #else
172 
173  /* Catch error condition */
174  if (src == NULL || dst == NULL) {
175  if (src == NULL)
176  G_warning(_("No source buffer"));
177 
178  if (dst == NULL)
179  G_warning(_("No destination buffer"));
180  return -2;
181  }
182 
183  /* Don't do anything if either of these are true */
184  if (src_sz <= 0 || dst_sz <= 0) {
185  if (src_sz <= 0)
186  G_warning(_("Invalid source buffer size %d"), src_sz);
187  if (dst_sz <= 0)
188  G_warning(_("Invalid destination buffer size %d"), dst_sz);
189  return 0;
190  }
191 
192  /* Do single pass decompress */
193  err = ZSTD_decompress((char *)dst, dst_sz, (char *)src, src_sz);
194 
195  if (err <= 0 || ZSTD_isError(err)) {
196  G_warning(_("ZSTD compression error %d: %s"),
197  err, ZSTD_getErrorName(err));
198  return -1;
199  }
200 
201  /* Number of bytes inflated to output stream is return value */
202  nbytes = err;
203 
204  if (nbytes != dst_sz) {
205  /* TODO: it is not an error if destination is larger than needed */
206  G_warning(_("Got uncompressed size %d, expected %d"), (int)nbytes, dst_sz);
207  return -1;
208  }
209 
210  return nbytes;
211 #endif
212 }
213 
214 
215 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
int G_zstd_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprzstd.c:88
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
char * dst
Definition: lz4.h:599
#define NULL
Definition: ccmath.h:32
int G_zstd_compress_bound(int src_sz)
Definition: cmprzstd.c:74
#define G_calloc(m, n)
Definition: defs/gis.h:113
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
int G_zstd_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprzstd.c:163
void G_warning(const char *,...) __attribute__((format(printf
#define _(str)
Definition: glocale.h:10