GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-2653d7b383
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 int G_bz2_compress_bound(int src_sz)
73 {
74  /* from the documentation:
75  * To guarantee that the compressed data will fit in its buffer,
76  * allocate an output buffer of size 1% larger than the uncompressed data,
77  * plus six hundred extra bytes.
78  * bzip2 does not provide a compressbound fn
79  * and apparently does not have a fast version if destLen is
80  * large enough to hold a worst case result
81  */
82  return src_sz;
83 }
84 
85 int G_bz2_compress(unsigned char *src, int src_sz, unsigned char *dst,
86  int dst_sz)
87 {
88  int err;
89  int buf_sz;
90  unsigned int i, nbytes;
91  unsigned char *buf;
92 
93 #ifndef HAVE_BZLIB_H
95  _("GRASS needs to be compiled with BZIP2 for BZIP2 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 1% + 600 bytes bigger for single pass compression
119  */
120  buf = dst;
121  buf_sz = G_bz2_compress_bound(src_sz);
122  if (buf_sz > dst_sz) {
123  G_warning(
124  "G_bz2_compress(): programmer error, destination is too small");
125  if (NULL ==
126  (buf = (unsigned char *)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 G_bz2_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
169 {
170  int err;
171  unsigned int nbytes;
172 
173 #ifndef HAVE_BZLIB_H
175  _("GRASS needs to be compiled with BZIP2 for BZIP2 compression"));
176  return -2;
177 #else
178 
179  /* Catch error condition */
180  if (src == NULL || dst == NULL) {
181  if (src == NULL)
182  G_warning(_("No source buffer"));
183 
184  if (dst == NULL)
185  G_warning(_("No destination buffer"));
186  return -2;
187  }
188 
189  /* Don't do anything if either of these are true */
190  if (src_sz <= 0 || dst_sz <= 0) {
191  if (src_sz <= 0)
192  G_warning(_("Invalid source buffer size %d"), src_sz);
193  if (dst_sz <= 0)
194  G_warning(_("Invalid destination buffer size %d"), dst_sz);
195  return 0;
196  }
197 
198  /* Do single pass decompression */
199  nbytes = dst_sz;
200  err = BZ2_bzBuffToBuffDecompress((char *)dst, &nbytes, /* destination */
201  (char *)src, src_sz, /* source */
202  0, /* small */
203  0); /* verbosity */
204 
205  if (err != BZ_OK) {
206  G_warning(_("BZIP2 version %s decompression error %d"),
207  BZ2_bzlibVersion(), err);
208  return -1;
209  }
210 
211  /* Number of bytes inflated to output stream is
212  * updated buffer size
213  */
214 
215  if (dst_sz < 0 || nbytes != (unsigned int)dst_sz) {
216  /* TODO: it is not an error if destination is larger than needed */
217  G_warning(_("Got uncompressed size %d, expected %d"), (int)nbytes,
218  dst_sz);
219  return -1;
220  }
221 
222  return nbytes;
223 #endif
224 }
225 
226 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
#define NULL
Definition: ccmath.h:32
int G_bz2_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprbzip.c:85
int G_bz2_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprbzip.c:168
int G_bz2_compress_bound(int src_sz)
Definition: cmprbzip.c:72
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