GRASS GIS 7 Programmer's Manual  7.2.0(2016)-exported
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  * COPYRIGHT: (C) 2015 by the GRASS Development Team
14  *
15  * This program is free software under the GNU General Public
16  * License (version 2 or greater). Read the file COPYING that
17  * comes with GRASS for details.
18  *
19  *****************************************************************************/
20 
21 /********************************************************************
22  * Compression methods: *
23  * 1 : RLE (generic Run-Length Encoding of single bytes) *
24  * 2 : ZLIB's DEFLATE (good speed and compression) *
25  * 3 : LZ4 (fastest, low compression) *
26  * 4 : BZIP2 (slowest, high compression) *
27  * *
28  * int *
29  * G_read_compressed (fd, rbytes, dst, nbytes, compression_type) *
30  * int fd, rbytes, nbytes; *
31  * unsigned char *dst; *
32  * ---------------------------------------------------------------- *
33  * This is the basic function for reading a compressed chunk of a *
34  * data file. The file descriptor should be in the proper location *
35  * and the 'dst' array should have enough space for the data. *
36  * 'nbytes' is the size of 'dst'. The 'rbytes' parameter is the *
37  * number of bytes to read (knowable from the offsets index). For *
38  * best results, 'nbytes' should be the exact amount of space *
39  * needed for the expansion. Too large a value of nbytes may cause *
40  * more data to be expanded than is desired. *
41  * Returns: The number of bytes decompressed into dst, or an error. *
42  * *
43  * Errors include: *
44  * -1 -- Error Reading or Decompressing data. *
45  * -2 -- Not enough space in dst. You must make dst larger *
46  * and then call the function again (remembering to *
47  * reset the file descriptor to it's proper location. *
48  * *
49  * ================================================================ *
50  * int *
51  * G_write_compressed (fd, src, nbytes, compression_type) *
52  * int fd, nbytes; *
53  * unsigned char *src; *
54  * ---------------------------------------------------------------- *
55  * This is the basic function for writing and compressing a data *
56  * chunk to a file. The file descriptor should be in the correct *
57  * location prior to this call. The function will compress 'nbytes' *
58  * of 'src' and write it to the file 'fd'. Returns the number of *
59  * bytes written or an error code: *
60  * *
61  * Errors include: *
62  * -1 -- Compression Failed. *
63  * -2 -- Unable to write to file. *
64  * *
65  * ================================================================ *
66  * int *
67  * G_write_uncompressed (fd, src, nbytes) *
68  * int fd, nbytes; *
69  * unsigned char *src; *
70  * ---------------------------------------------------------------- *
71  * Works similar to G_write_compressed() except no attempt at *
72  * compression is made. This is quicker, but may result in larger *
73  * files. *
74  * Returns the number of bytes written, or -1 for an error. It will *
75  * return an error if it fails to write nbytes. Otherwise, the *
76  * return value will always be nbytes + 1 (for compression flag). *
77  * *
78  ********************************************************************
79  */
80 
81 #include <grass/config.h>
82 
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <unistd.h>
87 #include <grass/gis.h>
88 #include <grass/glocale.h>
89 
90 #include "compress.h"
91 
92 #define G_COMPRESSED_NO (unsigned char)'0'
93 #define G_COMPRESSED_YES (unsigned char)'1'
94 
95 /* get compressor number
96  * return -1 on error
97  * return number >= 0 for known processor */
99 {
100  int i;
101 
102  if (!name)
103  return -1;
104 
105  for (i = 0; compressor[i].name ; i++) {
106  if (G_strcasecmp(name, compressor[i].name) == 0)
107  return i;
108  }
109 
110  return -1;
111 }
112 
113 /* get compressor name
114  * return NULL on error
115  * return string (name) of known processor */
116 char *G_compressor_name(int number)
117 {
118  if (number < 0 || number >= n_compressors)
119  return NULL;
120 
121  return compressor[number].name;
122 }
123 
124 /* check compressor number
125  * return -1 on error
126  * return 0 known but not available
127  * return 1 known and available */
128 int G_check_compressor(int number)
129 {
130  if (number < 0 || number >= n_compressors) {
131  G_warning(_("Request for unsupported compressor"));
132  return -1;
133  }
134 
135  return compressor[number].available;
136 }
137 
138 int
139 G_no_compress(unsigned char *src, int src_sz, unsigned char *dst,
140  int dst_sz)
141 {
142  /* Catch errors early */
143  if (src == NULL || dst == NULL)
144  return -1;
145 
146  /* Don't do anything if src is empty */
147  if (src_sz <= 0)
148  return 0;
149 
150  /* dst too small */
151  if (dst_sz < src_sz)
152  return -2;
153 
154  /* Copy the data from src to dst */
155  memcpy(dst, src, src_sz);
156 
157  return src_sz;
158 }
159 
160 int
161 G_no_expand(unsigned char *src, int src_sz, unsigned char *dst,
162  int dst_sz)
163 {
164  /* Catch errors early */
165  if (src == NULL || dst == NULL)
166  return -1;
167 
168  /* Don't do anything if src is empty */
169  if (src_sz <= 0)
170  return 0;
171 
172  /* dst too small */
173  if (dst_sz < src_sz)
174  return -2;
175 
176  /* Copy the data from src to dst */
177  memcpy(dst, src, src_sz);
178 
179  return src_sz;
180 }
181 
182 /* G_*_compress() returns
183  * > 0: number of bytes in dst
184  * 0: nothing done
185  * -1: error
186  * -2: dst too small
187  */
188 int
189 G_compress(unsigned char *src, int src_sz, unsigned char *dst,
190  int dst_sz, int number)
191 {
192  if (number < 0 || number >= n_compressors) {
193  G_fatal_error(_("Request for unsupported compressor"));
194  return -1;
195  }
196 
197  return compressor[number].compress(src, src_sz, dst, dst_sz);
198 }
199 
200 /* G_*_expand() returns
201  * > 0: number of bytes in dst
202  * -1: error
203  */
204 int
205 G_expand(unsigned char *src, int src_sz, unsigned char *dst,
206  int dst_sz, int number)
207 {
208  if (number < 0 || number >= n_compressors) {
209  G_fatal_error(_("Request for unsupported compressor"));
210  return -1;
211  }
212 
213  return compressor[number].expand(src, src_sz, dst, dst_sz);
214 }
215 
216 int G_read_compressed(int fd, int rbytes, unsigned char *dst, int nbytes,
217  int compressor)
218 {
219  int bsize, nread, err;
220  unsigned char *b;
221 
222  if (dst == NULL || nbytes < 0)
223  return -2;
224 
225  bsize = rbytes;
226 
227  /* Our temporary input buffer for read */
228  if (NULL == (b = (unsigned char *)
229  G_calloc(bsize, sizeof(unsigned char))))
230  return -1;
231 
232  /* Read from the file until we get our bsize or an error */
233  nread = 0;
234  do {
235  err = read(fd, b + nread, bsize - nread);
236  if (err >= 0)
237  nread += err;
238  } while (err > 0 && nread < bsize);
239 
240  /* If the bsize if less than rbytes and we didn't get an error.. */
241  if (nread < rbytes && err > 0) {
242  G_free(b);
243  return -1;
244  }
245 
246  /* Test if row is compressed */
247  if (b[0] == G_COMPRESSED_NO) {
248  /* Then just copy it to dst */
249  for (err = 0; err < nread - 1 && err < nbytes; err++)
250  dst[err] = b[err + 1];
251 
252  G_free(b);
253  return (nread - 1);
254  }
255  else if (b[0] != G_COMPRESSED_YES) {
256  /* We're not at the start of a row */
257  G_free(b);
258  return -1;
259  }
260  /* Okay it's a compressed row */
261 
262  /* Just call G_expand() with the buffer we read,
263  * Account for first byte being a flag
264  */
265  err = G_expand(b + 1, bsize - 1, dst, nbytes, compressor);
266 
267  /* We're done with b */
268  G_free(b);
269 
270  /* Return whatever G_expand() returned */
271  return err;
272 
273 } /* G_read_compressed() */
274 
275 int G_write_compressed(int fd, unsigned char *src, int nbytes,
276  int compressor)
277 {
278  int dst_sz, nwritten, err;
279  unsigned char *dst, compressed;
280 
281  /* Catch errors */
282  if (src == NULL || nbytes < 0)
283  return -1;
284 
285  dst_sz = nbytes;
286  if (NULL == (dst = (unsigned char *)
287  G_calloc(dst_sz, sizeof(unsigned char))))
288  return -1;
289 
290  /* Now just call G_compress() */
291  err = G_compress(src, nbytes, dst, dst_sz, compressor);
292 
293  /* If compression succeeded write compressed row,
294  * otherwise write uncompressed row. Compression will fail
295  * if dst is too small (i.e. compressed data is larger)
296  */
297  if (err > 0 && err <= dst_sz) {
298  dst_sz = err;
299  /* Write the compression flag */
300  compressed = G_COMPRESSED_YES;
301  if (write(fd, &compressed, 1) != 1) {
302  G_free(dst);
303  return -1;
304  }
305  nwritten = 0;
306  do {
307  err = write(fd, dst + nwritten, dst_sz - nwritten);
308  if (err >= 0)
309  nwritten += err;
310  } while (err > 0 && nwritten < dst_sz);
311  /* Account for extra byte */
312  nwritten++;
313  }
314  else {
315  /* Write compression flag */
316  compressed = G_COMPRESSED_NO;
317  if (write(fd, &compressed, 1) != 1) {
318  G_free(dst);
319  return -1;
320  }
321  nwritten = 0;
322  do {
323  err = write(fd, src + nwritten, nbytes - nwritten);
324  if (err >= 0)
325  nwritten += err;
326  } while (err > 0 && nwritten < nbytes);
327  /* Account for extra byte */
328  nwritten++;
329  } /* if (err > 0) */
330 
331  /* Done with the dst buffer */
332  G_free(dst);
333 
334  /* If we didn't write all the data return an error */
335  if (err < 0)
336  return -2;
337 
338  return nwritten;
339 } /* G_write_compressed() */
340 
341 int G_write_uncompressed(int fd, const unsigned char *src, int nbytes)
342 {
343  int err, nwritten;
344  unsigned char compressed;
345 
346  /* Catch errors */
347  if (src == NULL || nbytes < 0)
348  return -1;
349 
350  /* Write the compression flag */
351  compressed = G_COMPRESSED_NO;
352  if (write(fd, &compressed, 1) != 1)
353  return -1;
354 
355  /* Now write the data */
356  nwritten = 0;
357  do {
358  err = write(fd, src + nwritten, nbytes - nwritten);
359  if (err > 0)
360  nwritten += err;
361  } while (err > 0 && nwritten < nbytes);
362 
363  if (err < 0 || nwritten != nbytes)
364  return -1;
365 
366  /* Account for extra compressed flag */
367  nwritten++;
368 
369  /* That's all */
370  return nwritten;
371 
372 } /* G_write_uncompressed() */
373 
374 
375 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
int G_strcasecmp(const char *x, const char *y)
String compare ignoring case (upper or lower)
Definition: strings.c:46
struct compressor_list compressor[]
Definition: compress.h:41
int G_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz, int number)
Definition: compress.c:189
compress_fn * compress
Definition: compress.h:27
char * G_compressor_name(int number)
Definition: compress.c:116
expand_fn * expand
Definition: compress.h:28
int G_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz, int number)
Definition: compress.c:205
char * dst
Definition: lz4.h:354
#define NULL
Definition: ccmath.h:32
int G_write_compressed(int fd, unsigned char *src, int nbytes, int compressor)
Definition: compress.c:275
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:159
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
Definition: symbol/read.c:220
int G_no_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: compress.c:161
double b
int G_write_uncompressed(int fd, const unsigned char *src, int nbytes)
Definition: compress.c:341
char * name
Definition: compress.h:29
int G_read_compressed(int fd, int rbytes, unsigned char *dst, int nbytes, int compressor)
Definition: compress.c:216
#define G_COMPRESSED_NO
Definition: compress.c:92
int G_no_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: compress.c:139
#define G_COMPRESSED_YES
Definition: compress.c:93
int G_check_compressor(int number)
Definition: compress.c:128
int G_compressor_number(char *name)
Definition: compress.c:98
const char * name
Definition: named_colr.c:7
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:203