GRASS GIS 8 Programmer's Manual  8.4.0dev(2024)-535c39c9fc
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 G_rle_compress(unsigned char *src, int src_sz, unsigned char *dst,
74  int dst_sz)
75 {
76  int i, nbytes;
77  unsigned char prev_b;
78  int cnt;
79 
80  /* Catch errors early */
81  if (src == NULL || dst == NULL)
82  return -1;
83 
84  /* Don't do anything if src is empty or smaller than 4 bytes */
85  if (src_sz <= 3)
86  return 0;
87 
88  /* modified RLE:
89  * unit is 1 byte, only sequences longer than 1 are encoded
90  * single occurrences don't have a following count
91  * multiple occurrences are twice in dst, followed by the count
92  * example:
93  * ABBCCC
94  * is encoded as
95  * ABB2CC3
96  */
97 
98  prev_b = src[0];
99  cnt = 1;
100  nbytes = 0;
101  for (i = 1; i < src_sz; i++) {
102  if (prev_b != src[i] || cnt == 255) {
103  /* write to dst */
104  if (cnt == 1) {
105  if (nbytes >= dst_sz)
106  return -2;
107  dst[nbytes++] = prev_b;
108  }
109  else {
110  /* cnt > 1 */
111  if (nbytes >= dst_sz - 2)
112  return -2;
113  dst[nbytes++] = prev_b;
114  dst[nbytes++] = prev_b;
115  dst[nbytes++] = (unsigned char)cnt;
116  }
117  cnt = 0;
118  }
119  prev_b = src[i];
120  cnt++;
121  }
122  /* write out the last sequence */
123  if (cnt == 1) {
124  if (nbytes >= dst_sz)
125  return -2;
126  dst[nbytes++] = prev_b;
127  }
128  else {
129  if (nbytes >= dst_sz - 2)
130  return -2;
131  dst[nbytes++] = prev_b;
132  dst[nbytes++] = prev_b;
133  dst[nbytes++] = (unsigned char)cnt;
134  }
135 
136  return nbytes;
137 }
138 
139 int G_rle_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
140 {
141  int i, j, nbytes, cnt;
142  unsigned char prev_b;
143 
144  /* Catch errors early */
145  if (src == NULL || dst == NULL)
146  return -1;
147 
148  /* Don't do anything if src is empty */
149  if (src_sz <= 0)
150  return 0;
151 
152  /* RLE expand */
153  prev_b = src[0];
154  cnt = 1;
155  nbytes = 0;
156  i = 1;
157  while (i < src_sz) {
158  /* single occurrences don't have a following count
159  * multiple occurrences are twice in src, followed by the count */
160  if (cnt == 2) {
161  if (i >= src_sz)
162  return -1;
163  cnt = src[i];
164  if (nbytes + cnt > dst_sz)
165  return -1;
166  for (j = 0; j < cnt; j++) {
167  dst[nbytes++] = prev_b;
168  }
169  cnt = 0;
170  i++;
171  if (i >= src_sz)
172  return nbytes;
173  }
174  if (cnt == 1) {
175  if (prev_b != src[i]) {
176  if (nbytes + cnt > dst_sz)
177  return -1;
178  dst[nbytes++] = prev_b;
179  cnt = 0;
180  }
181  }
182  prev_b = src[i];
183  cnt++;
184  i++;
185  }
186  if (nbytes >= dst_sz)
187  return -1;
188  if (cnt == 1)
189  dst[nbytes++] = prev_b;
190 
191  return nbytes;
192 }
193 
194 /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
#define NULL
Definition: ccmath.h:32
int G_rle_compress_bound(int src_sz)
Definition: cmprrle.c:68
int G_rle_compress(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprrle.c:73
int G_rle_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprrle.c:139