GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-112dd97adf
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 int G_zstd_compress_bound(int src_sz)
73 {
74  /* ZSTD has a fast version if destLen is large enough
75  * to hold a worst case result
76  */
77 #ifndef HAVE_ZSTD_H
79  _("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 G_zstd_compress(unsigned char *src, int src_sz, unsigned char *dst,
87  int dst_sz)
88 {
89  int err, nbytes, buf_sz;
90  unsigned char *buf;
91 
92 #ifndef HAVE_ZSTD_H
94  _("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(
122  "G_zstd_compress(): programmer error, destination is too small");
123  if (NULL ==
124  (buf = (unsigned char *)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"), err,
135  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 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
169  _("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"), err,
197  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,
207  dst_sz);
208  return -1;
209  }
210 
211  return nbytes;
212 #endif
213 }
214 
215 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
#define NULL
Definition: ccmath.h:32
int G_zstd_compress_bound(int src_sz)
Definition: cmprzstd.c:72
int G_zstd_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprzstd.c:86
int G_zstd_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprzstd.c:162
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_calloc(m, n)
Definition: defs/gis.h:95
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
#define _(str)
Definition: glocale.h:10
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:216