GRASS GIS 7 Programmer's Manual  7.9.dev(2021)-e5379bbd7
cmprrle.c
Go to the documentation of this file.
1 /*
2  ****************************************************************************
3  * -- GRASS Development Team --
4  *
5  * MODULE: GRASS gis library
6  * FILENAME: cmprrle.c
7  * AUTHOR(S): Markus Metz
8  * PURPOSE: To provide generic RLE for compressing and
9  * decompressing data. Its primary use is in
10  * the storage and reading of GRASS rasters.
11  *
12  * ALGORITHM: Run Length Encoding
13  * DATE CREATED: Dec 18 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_rle_compress (src, srz_sz, dst, dst_sz) *
25  * int src_sz, dst_sz; *
26  * unsigned char *src, *dst; *
27  * ---------------------------------------------------------------- *
28  * This function compresses data with RLE. *
29  * It uses an all or nothing call. *
30  * If you need a continuous compression scheme, you'll have to code *
31  * your own. *
32  * *
33  * The function either returns the number of bytes of compressed *
34  * data in dst, or an error code. *
35  * *
36  * Errors include: *
37  * -1 -- Compression failed. *
38  * -2 -- dst is too small. *
39  * *
40  * ================================================================ *
41  * int *
42  * G_rle_expand (src, src_sz, dst, dst_sz) *
43  * int src_sz, dst_sz; *
44  * unsigned char *src, *dst; *
45  * ---------------------------------------------------------------- *
46  * This function decompresses data compressed with RLE. *
47  * It is equivalent to a single pass call to an external expansion *
48  * function. *
49  * If you need a continuous expansion scheme, you'll have to code *
50  * your own. *
51  * *
52  * The function returns the number of bytes expanded into 'dst' or *
53  * and error code. *
54  * *
55  * Errors include: *
56  * -1 -- Expansion failed. *
57  * *
58  ********************************************************************
59  */
60 
61 #include <grass/config.h>
62 
63 #include <grass/gis.h>
64 #include <grass/glocale.h>
65 
66 /* no fast mode if destination is large enough to hold
67  * worst case compression */
68 int G_rle_compress_bound(int src_sz)
69 {
70  return ((src_sz >> 1) * 3 + (src_sz & 1));
71 }
72 
73 int
74 G_rle_compress(unsigned char *src, int src_sz, unsigned char *dst,
75  int dst_sz)
76 {
77  int i, nbytes;
78  unsigned char prev_b;
79  int cnt;
80 
81  /* Catch errors early */
82  if (src == NULL || dst == NULL)
83  return -1;
84 
85  /* Don't do anything if src is empty or smaller than 4 bytes */
86  if (src_sz <= 3)
87  return 0;
88 
89  /* modified RLE:
90  * unit is 1 byte, only sequences longer than 1 are encoded
91  * single occurrences don't have a following count
92  * multiple occurrences are twice in dst, followed by the count
93  * example:
94  * ABBCCC
95  * is encoded as
96  * ABB2CC3
97  */
98 
99  prev_b = src[0];
100  cnt = 1;
101  nbytes = 0;
102  for (i = 1; i < src_sz; i++) {
103  if (prev_b != src[i] || cnt == 255) {
104  /* write to dst */
105  if (cnt == 1) {
106  if (nbytes >= dst_sz)
107  return -2;
108  dst[nbytes++] = prev_b;
109  }
110  else {
111  /* cnt > 1 */
112  if (nbytes >= dst_sz - 2)
113  return -2;
114  dst[nbytes++] = prev_b;
115  dst[nbytes++] = prev_b;
116  dst[nbytes++] = (unsigned char) cnt;
117  }
118  cnt = 0;
119  }
120  prev_b = src[i];
121  cnt++;
122  }
123  /* write out the last sequence */
124  if (cnt == 1) {
125  if (nbytes >= dst_sz)
126  return -2;
127  dst[nbytes++] = prev_b;
128  }
129  else {
130  if (nbytes >= dst_sz - 2)
131  return -2;
132  dst[nbytes++] = prev_b;
133  dst[nbytes++] = prev_b;
134  dst[nbytes++] = (unsigned char) cnt;
135  }
136 
137  return nbytes;
138 }
139 
140 int
141 G_rle_expand(unsigned char *src, int src_sz, unsigned char *dst,
142  int dst_sz)
143 {
144  int i, j, nbytes, cnt;
145  unsigned char prev_b;
146 
147  /* Catch errors early */
148  if (src == NULL || dst == NULL)
149  return -1;
150 
151  /* Don't do anything if src is empty */
152  if (src_sz <= 0)
153  return 0;
154 
155  /* RLE expand */
156  prev_b = src[0];
157  cnt = 1;
158  nbytes = 0;
159  i = 1;
160  while (i < src_sz) {
161  /* single occurrences don't have a following count
162  * multiple occurrences are twice in src, followed by the count */
163  if (cnt == 2) {
164  if (i >= src_sz)
165  return -1;
166  cnt = src[i];
167  if (nbytes + cnt > dst_sz)
168  return -1;
169  for (j = 0; j < cnt; j++) {
170  dst[nbytes++] = prev_b;
171  }
172  cnt = 0;
173  i++;
174  if (i >= src_sz)
175  return nbytes;
176  }
177  if (cnt == 1) {
178  if (prev_b != src[i]) {
179  if (nbytes + cnt > dst_sz)
180  return -1;
181  dst[nbytes++] = prev_b;
182  cnt = 0;
183  }
184  }
185  prev_b = src[i];
186  cnt++;
187  i++;
188  }
189  if (nbytes >= dst_sz)
190  return -1;
191  if (cnt == 1)
192  dst[nbytes++] = prev_b;
193 
194  return nbytes;
195 }
196 
197 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
int G_rle_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprrle.c:74
char * dst
Definition: lz4.h:599
#define NULL
Definition: ccmath.h:32
int G_rle_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprrle.c:141
int G_rle_compress_bound(int src_sz)
Definition: cmprrle.c:68