GRASS 8 Programmer's Manual 8.6.0dev(2026)-c83afef6d3
Loading...
Searching...
No Matches
compress.c
Go to the documentation of this file.
1/*
2 ****************************************************************************
3 * -- GRASS Development Team --
4 *
5 * MODULE: GRASS gis library
6 * FILENAME: compress.c
7 * AUTHOR(S): Markus Metz
8 * PURPOSE: To provide an interface for compressing and
9 * decompressing data using various methods. Its primary
10 * use is in the storage and reading of GRASS rasters.
11 *
12 * DATE CREATED: Dec 17 2015
13 * SPDX-FileCopyrightText: 2015 GRASS Development Team
14 * SPDX-License-Identifier: GPL-2.0-or-later
15 *
16 *****************************************************************************/
17
18/********************************************************************
19 * Compression methods: *
20 * 1 : RLE (generic Run-Length Encoding of single bytes) *
21 * 2 : ZLIB's DEFLATE (good speed and compression) *
22 * 3 : LZ4 (fastest, low compression) *
23 * 4 : BZIP2 (slowest, high compression) *
24 * 5 : ZSTD (faster than ZLIB, higher compression than ZLIB) *
25 * *
26 * int *
27 * G_read_compressed (fd, rbytes, dst, nbytes, compression_type) *
28 * int fd, rbytes, nbytes; *
29 * unsigned char *dst; *
30 * ---------------------------------------------------------------- *
31 * This is the basic function for reading a compressed chunk of a *
32 * data file. The file descriptor should be in the proper location *
33 * and the 'dst' array should have enough space for the data. *
34 * 'nbytes' is the size of 'dst'. The 'rbytes' parameter is the *
35 * number of bytes to read (knowable from the offsets index). For *
36 * best results, 'nbytes' should be the exact amount of space *
37 * needed for the expansion. Too large a value of nbytes may cause *
38 * more data to be expanded than is desired. *
39 * Returns: The number of bytes decompressed into dst, or an error. *
40 * *
41 * Errors include: *
42 * -1 -- Error Reading or Decompressing data. *
43 * -2 -- Not enough space in dst. You must make dst larger *
44 * and then call the function again (remembering to *
45 * reset the file descriptor to it's proper location. *
46 * *
47 * ================================================================ *
48 * int *
49 * G_write_compressed (fd, src, nbytes, compression_type) *
50 * int fd, nbytes; *
51 * unsigned char *src; *
52 * ---------------------------------------------------------------- *
53 * This is the basic function for writing and compressing a data *
54 * chunk to a file. The file descriptor should be in the correct *
55 * location prior to this call. The function will compress 'nbytes' *
56 * of 'src' and write it to the file 'fd'. Returns the number of *
57 * bytes written or an error code: *
58 * *
59 * Errors include: *
60 * -1 -- Compression Failed. *
61 * -2 -- Unable to write to file. *
62 * *
63 * ================================================================ *
64 * int *
65 * G_write_uncompressed (fd, src, nbytes) *
66 * int fd, nbytes; *
67 * unsigned char *src; *
68 * ---------------------------------------------------------------- *
69 * Works similar to G_write_compressed() except no attempt at *
70 * compression is made. This is quicker, but may result in larger *
71 * files. *
72 * Returns the number of bytes written, or -1 for an error. It will *
73 * return an error if it fails to write nbytes. Otherwise, the *
74 * return value will always be nbytes + 1 (for compression flag). *
75 * *
76 ********************************************************************
77 */
78
79#include <grass/config.h>
80
81#include <stdio.h>
82#include <stdlib.h>
83#include <string.h>
84#include <errno.h>
85#include <unistd.h>
86#include <grass/gis.h>
87#include <grass/glocale.h>
88
89#include "compress.h"
90
91#define G_COMPRESSED_NO (unsigned char)'0'
92#define G_COMPRESSED_YES (unsigned char)'1'
93
94/* get compressor number
95 * return -1 on error
96 * return number >= 0 for known processor */
98{
99 int i;
100
101 if (!name)
102 return -1;
103
104 for (i = 0; compressor[i].name; i++) {
105 if (G_strcasecmp(name, compressor[i].name) == 0)
106 return i;
107 }
108
109 return -1;
110}
111
112/* get compressor name
113 * return NULL on error
114 * return string (name) of known processor */
115char *G_compressor_name(int number)
116{
117 if (number < 0 || number >= n_compressors)
118 return NULL;
119
120 return compressor[number].name;
121}
122
124{
125#ifdef HAVE_ZSTD_H
126 /* ZSTD */
127 return 5;
128#endif
129 /* ZLIB */
130 return 2;
131}
132
133/* check compressor number
134 * return -1 on error
135 * return 0 known but not available
136 * return 1 known and available */
137int G_check_compressor(int number)
138{
139 if (number < 0 || number >= n_compressors) {
140 G_warning(_("Request for unsupported compressor"));
141 return -1;
142 }
143
144 return compressor[number].available;
145}
146
148{
149 return src_sz;
150}
151
152int G_no_compress(unsigned char *src, int src_sz, unsigned char *dst,
153 int dst_sz)
154{
155 /* Catch errors early */
156 if (src == NULL || dst == NULL)
157 return -1;
158
159 /* Don't do anything if src is empty */
160 if (src_sz <= 0)
161 return 0;
162
163 /* dst too small */
164 if (dst_sz < src_sz)
165 return -2;
166
167 /* Copy the data from src to dst */
168 memcpy(dst, src, src_sz);
169
170 return src_sz;
171}
172
173int G_no_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
174{
175 /* Catch errors early */
176 if (src == NULL || dst == NULL)
177 return -1;
178
179 /* Don't do anything if src is empty */
180 if (src_sz <= 0)
181 return 0;
182
183 /* dst too small */
184 if (dst_sz < src_sz)
185 return -2;
186
187 /* Copy the data from src to dst */
188 memcpy(dst, src, src_sz);
189
190 return src_sz;
191}
192
193/* G_*_compress_bound() returns an upper bound on the compressed size
194 * which can be larger than the input size
195 * some compressors are a bit faster if the size of the destination
196 * is at least the upper bound (no need to test for buffer overflow)
197 * read comments on the specific compressor interfaces
198 */
199int G_compress_bound(int src_sz, int number)
200{
201 if (number < 0 || number >= n_compressors) {
202 G_fatal_error(_("Request for unsupported compressor"));
203 return -1;
204 }
205
206 return compressor[number].bound(src_sz);
207}
208
209/* G_*_compress() returns
210 * > 0: number of bytes in dst
211 * 0: nothing done
212 * -1: error
213 * -2: dst too small
214 */
215int G_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz,
216 int number)
217{
218 if (number < 0 || number >= n_compressors) {
219 G_fatal_error(_("Request for unsupported compressor"));
220 return -1;
221 }
222
223 return compressor[number].compress(src, src_sz, dst, dst_sz);
224}
225
226/* G_*_expand() returns
227 * > 0: number of bytes in dst
228 * -1: error
229 */
230int G_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz,
231 int number)
232{
233 if (number < 0 || number >= n_compressors) {
234 G_fatal_error(_("Request for unsupported compressor"));
235 return -1;
236 }
237
238 return compressor[number].expand(src, src_sz, dst, dst_sz);
239}
240
241int G_read_compressed(int fd, int rbytes, unsigned char *dst, int nbytes,
242 int number)
243{
244 int bsize, nread, err;
245 unsigned char *b;
246
247 if (dst == NULL || nbytes <= 0) {
248 if (dst == NULL)
249 G_warning(_("No destination buffer allocated"));
250 if (nbytes <= 0)
251 G_warning(_("Invalid destination buffer size %d"), nbytes);
252 return -2;
253 }
254
255 if (rbytes <= 0) {
256 G_warning(_("Invalid read size %d"), nbytes);
257 return -2;
258 }
259
260 bsize = rbytes;
261
262 /* Our temporary input buffer for read */
263 if (NULL == (b = (unsigned char *)G_calloc(bsize, sizeof(unsigned char))))
264 return -1;
265
266 /* Read from the file until we get our bsize or an error */
267 nread = 0;
268 do {
269 err = read(fd, b + nread, bsize - nread);
270 if (err >= 0)
271 nread += err;
272 } while (err > 0 && nread < bsize);
273
274 if (err <= 0) {
275 if (err == 0)
276 G_warning(_("Unable to read %d bytes: end of file"), rbytes);
277 else
278 G_warning(_("Unable to read %d bytes: %s"), rbytes,
279 strerror(errno));
280 return -1;
281 }
282
283 /* If the bsize if less than rbytes and we didn't get an error.. */
284 if (nread < rbytes) {
285 G_free(b);
286 G_warning("Unable to read %d bytes, got %d bytes", rbytes, nread);
287 return -1;
288 }
289
290 /* Test if row is compressed */
291 if (b[0] == G_COMPRESSED_NO) {
292 /* Then just copy it to dst */
293 for (err = 0; err < nread - 1 && err < nbytes; err++)
294 dst[err] = b[err + 1];
295
296 G_free(b);
297 return (nread - 1);
298 }
299 else if (b[0] != G_COMPRESSED_YES) {
300 /* We're not at the start of a row */
301 G_free(b);
302 G_warning("Read error: We're not at the start of a row");
303 return -1;
304 }
305 /* Okay it's a compressed row */
306
307 /* Just call G_expand() with the buffer we read,
308 * Account for first byte being a flag
309 */
310 err = G_expand(b + 1, bsize - 1, dst, nbytes, number);
311
312 /* We're done with b */
313 G_free(b);
314
315 /* Return whatever G_expand() returned */
316 return err;
317
318} /* G_read_compressed() */
319
320int G_write_compressed(int fd, unsigned char *src, int nbytes, int number)
321{
322 unsigned char *dst, compressed;
323
324 /* Catch errors */
325 if (src == NULL || nbytes < 0) {
326 if (src == NULL)
327 G_warning(_("No source buffer"));
328 if (nbytes <= 0)
329 G_warning(_("Invalid source buffer size %d"), nbytes);
330 return -1;
331 }
332
333 /* get upper bound of compressed size */
334 int dst_sz = G_compress_bound(nbytes, number);
335 if (NULL ==
336 (dst = (unsigned char *)G_calloc(dst_sz, sizeof(unsigned char))))
337 return -1;
338
339 /* Now just call G_compress() */
340 ssize_t err = G_compress(src, nbytes, dst, dst_sz, number);
341 size_t nwritten = 0;
342
343 /* If compression succeeded write compressed row,
344 * otherwise write uncompressed row. Compression will fail
345 * if dst is too small (i.e. compressed data is larger)
346 */
347 if (err > 0 && err < nbytes) {
348 dst_sz = err;
349 /* Write the compression flag */
350 compressed = G_COMPRESSED_YES;
351 if (write(fd, &compressed, 1) != 1) {
352 G_free(dst);
353 G_warning(_("Unable to write compression flag"));
354 return -1;
355 }
356 do {
357 err = write(fd, dst + nwritten, dst_sz - nwritten);
358 if (err >= 0)
359 nwritten += err;
360 } while (err > 0 && nwritten < (size_t)dst_sz);
361 if (err <= 0) {
362 if (err == 0)
363 G_warning(_("Unable to write %d bytes: nothing written"),
364 dst_sz);
365 else
366 G_warning(_("Unable to write %d bytes: %s"), dst_sz,
367 strerror(errno));
368 }
369 /* Account for extra byte */
370 nwritten++;
371 }
372 else {
373 /* Write compression flag */
374 compressed = G_COMPRESSED_NO;
375 if (write(fd, &compressed, 1) != 1) {
376 G_free(dst);
377 G_warning(_("Unable to write compression flag"));
378 return -1;
379 }
380 do {
381 err = write(fd, src + nwritten, nbytes - nwritten);
382 if (err >= 0)
383 nwritten += err;
384 } while (err > 0 && nwritten < (size_t)nbytes);
385 if (err <= 0) {
386 if (err == 0)
387 G_warning(_("Unable to write %d bytes: nothing written"),
388 nbytes);
389 else
390 G_warning(_("Unable to write %d bytes: %s"), nbytes,
391 strerror(errno));
392 }
393 /* Account for extra byte */
394 nwritten++;
395 } /* if (err > 0) */
396
397 /* Done with the dst buffer */
398 G_free(dst);
399
400 /* If we didn't write all the data return an error */
401 if (err < 0)
402 return -2;
403
404 return (int)nwritten;
405} /* G_write_compressed() */
406
407int G_write_uncompressed(int fd, const unsigned char *src, int nbytes)
408{
409 /* Catch errors */
410 if (src == NULL || nbytes < 0)
411 return -1;
412
413 /* Write the compression flag */
414 unsigned char compressed = G_COMPRESSED_NO;
415 if (write(fd, &compressed, 1) != 1) {
416 G_warning(_("Unable to write compression flag"));
417 return -1;
418 }
419
420 ssize_t err = 0;
421 size_t nwritten = 0;
422
423 /* Now write the data */
424 do {
425 err = write(fd, src + nwritten, nbytes - nwritten);
426 if (err > 0)
427 nwritten += err;
428 } while (err > 0 && nwritten < (size_t)nbytes);
429 if (err <= 0) {
430 if (err == 0)
431 G_warning(_("Unable to write %d bytes: nothing written"), nbytes);
432 else
433 G_warning(_("Unable to write %d bytes: %s"), nbytes,
434 strerror(errno));
435 }
436
437 if (err < 0 || nwritten != (size_t)nbytes)
438 return -1;
439
440 /* Account for extra compressed flag */
441 nwritten++;
442
443 /* That's all */
444 return (int)nwritten;
445
446} /* G_write_uncompressed() */
447
448/* vim: set softtabstop=4 shiftwidth=4 expandtab: */
#define NULL
Definition ccmath.h:32
AMI_err name(char **stream_name)
Definition ami_stream.h:426
int G_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz, int number)
Definition compress.c:215
char * G_compressor_name(int number)
Definition compress.c:115
int G_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz, int number)
Definition compress.c:230
int G_write_compressed(int fd, unsigned char *src, int nbytes, int number)
Definition compress.c:320
int G_default_compressor(void)
Definition compress.c:123
int G_write_uncompressed(int fd, const unsigned char *src, int nbytes)
Definition compress.c:407
int G_read_compressed(int fd, int rbytes, unsigned char *dst, int nbytes, int number)
Definition compress.c:241
int G_no_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition compress.c:152
#define G_COMPRESSED_YES
Definition compress.c:92
int G_compressor_number(char *name)
Definition compress.c:97
#define G_COMPRESSED_NO
Definition compress.c:91
int G_check_compressor(int number)
Definition compress.c:137
int G_no_compress_bound(int src_sz)
Definition compress.c:147
int G_no_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition compress.c:173
int G_compress_bound(int src_sz, int number)
Definition compress.c:199
struct compressor_list compressor[]
Definition compress.h:53
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:145
#define G_calloc(m, n)
Definition defs/gis.h:137
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int int G_strcasecmp(const char *, const char *)
String compare ignoring case (upper or lower)
Definition strings.c:45
#define _(str)
Definition glocale.h:10
const char * name
Definition named_colr.c:6
double b
Definition r_raster.c:37
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
#define read
Definition unistd.h:5
#define write
Definition unistd.h:6