GRASS GIS 8 Programmer's Manual  8.2.2dev(2023)-3d2c704037
cmprbzip.c
Go to the documentation of this file.
1 /*
2  ****************************************************************************
3  * -- GRASS Development Team --
4  *
5  * MODULE: GRASS gis library
6  * FILENAME: cmprbzip.c
7  * AUTHOR(S): Markus Metz
8  * PURPOSE: To provide an interface to libbzip2 for compressing and
9  * decompressing data. Its primary use is in
10  * the storage and reading of GRASS rasters.
11  *
12  * ALGORITHM: http://www.bzip.org
13  * DATE CREATED: Nov 19 2015
14  * COPYRIGHT: (C) 2015 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_bz2_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 bzip2 compression *
29  * function. 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 1% + 600 bytes larger than the data. This *
34  * may cause 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_bz2_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 bzip2 decompression *
50  * function. It uses a single pass call to inflate(). *
51  * If you need a continuous expansion scheme, you'll have to code *
52  * 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_BZLIB_H
66 #include <bzlib.h>
67 #endif
68 
69 #include <grass/gis.h>
70 #include <grass/glocale.h>
71 
72 
73 int
75 {
76  /* from the documentation:
77  * To guarantee that the compressed data will fit in its buffer,
78  * allocate an output buffer of size 1% larger than the uncompressed data,
79  * plus six hundred extra bytes.
80  * bzip2 does not provide a compressbound fn
81  * and apparently does not have a fast version if destLen is
82  * large enough to hold a worst case result
83  */
84  return src_sz;
85 }
86 
87 int
88 G_bz2_compress(unsigned char *src, int src_sz, unsigned char *dst,
89  int dst_sz)
90 {
91  int err;
92  int i, buf_sz;
93  unsigned int nbytes;
94  unsigned char *buf;
95 
96 #ifndef HAVE_BZLIB_H
97  G_fatal_error(_("GRASS needs to be compiled with BZIP2 for BZIP2 compression"));
98  return -1;
99 #else
100 
101  /* Catch errors early */
102  if (src == NULL || dst == NULL) {
103  if (src == NULL)
104  G_warning(_("No source buffer"));
105 
106  if (dst == NULL)
107  G_warning(_("No destination buffer"));
108  return -1;
109  }
110 
111  /* Don't do anything if either of these are true */
112  if (src_sz <= 0 || dst_sz <= 0) {
113  if (src_sz <= 0)
114  G_warning(_("Invalid source buffer size %d"), src_sz);
115  if (dst_sz <= 0)
116  G_warning(_("Invalid destination buffer size %d"), dst_sz);
117  return 0;
118  }
119 
120  /* Output buffer has to be 1% + 600 bytes bigger for single pass compression */
121  buf = dst;
122  buf_sz = G_bz2_compress_bound(src_sz);
123  if (buf_sz > dst_sz) {
124  G_warning("G_bz2_compress(): programmer error, destination is too small");
125  if (NULL == (buf = (unsigned char *)
126  G_calloc(buf_sz, sizeof(unsigned char))))
127  return -1;
128  }
129  else
130  buf_sz = dst_sz;
131 
132  /* Do single pass compression */
133  nbytes = buf_sz;
134  err = BZ2_bzBuffToBuffCompress((char *)buf, &nbytes, /* destination */
135  (char *)src, src_sz, /* source */
136  9, /* blockSize100k */
137  0, /* verbosity */
138  100); /* workFactor */
139 
140  if (err != BZ_OK) {
141  G_warning(_("BZIP2 version %s compression error %d"),
142  BZ2_bzlibVersion(), err);
143  if (buf != dst)
144  G_free(buf);
145  return -1;
146  }
147 
148  /* updated buf_sz is bytes of compressed data */
149  if (nbytes >= (unsigned int)src_sz) {
150  /* compression not possible */
151  if (buf != dst)
152  G_free(buf);
153  return -2;
154  }
155 
156  if (buf != dst) {
157  /* Copy the data from buf to dst */
158  for (i = 0; i < nbytes; i++)
159  dst[i] = buf[i];
160 
161  G_free(buf);
162  }
163 
164  return nbytes;
165 #endif
166 } /* G_bz2_compress() */
167 
168 int
169 G_bz2_expand(unsigned char *src, int src_sz, unsigned char *dst,
170  int dst_sz)
171 {
172  int err;
173  unsigned int nbytes;
174 
175 #ifndef HAVE_BZLIB_H
176  G_fatal_error(_("GRASS needs to be compiled with BZIP2 for BZIP2 compression"));
177  return -2;
178 #else
179 
180  /* Catch error condition */
181  if (src == NULL || dst == NULL) {
182  if (src == NULL)
183  G_warning(_("No source buffer"));
184 
185  if (dst == NULL)
186  G_warning(_("No destination buffer"));
187  return -2;
188  }
189 
190  /* Don't do anything if either of these are true */
191  if (src_sz <= 0 || dst_sz <= 0) {
192  if (src_sz <= 0)
193  G_warning(_("Invalid source buffer size %d"), src_sz);
194  if (dst_sz <= 0)
195  G_warning(_("Invalid destination buffer size %d"), dst_sz);
196  return 0;
197  }
198 
199 
200  /* Do single pass decompression */
201  nbytes = dst_sz;
202  err = BZ2_bzBuffToBuffDecompress((char *)dst, &nbytes, /* destination */
203  (char *)src, src_sz, /* source */
204  0, /* small */
205  0); /* verbosity */
206 
207  if (err != BZ_OK) {
208  G_warning(_("BZIP2 version %s decompression error %d"),
209  BZ2_bzlibVersion(), err);
210  return -1;
211  }
212 
213  /* Number of bytes inflated to output stream is
214  * updated buffer size
215  */
216 
217  if (nbytes != dst_sz) {
218  /* TODO: it is not an error if destination is larger than needed */
219  G_warning(_("Got uncompressed size %d, expected %d"), (int)nbytes, dst_sz);
220  return -1;
221  }
222 
223  return nbytes;
224 #endif
225 }
226 
227 
228 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
int G_bz2_compress_bound(int src_sz)
Definition: cmprbzip.c:74
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:149
char * dst
Definition: lz4.h:599
#define NULL
Definition: ccmath.h:32
#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_bz2_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprbzip.c:88
void G_warning(const char *,...) __attribute__((format(printf
#define _(str)
Definition: glocale.h:10
int G_bz2_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprbzip.c:169