GRASS GIS 8 Programmer's Manual 8.2.1(2023)-exported
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 */
68int G_rle_compress_bound(int src_sz)
69{
70 return ((src_sz >> 1) * 3 + (src_sz & 1));
71}
72
73int
74G_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
140int
141G_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: */
#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:74
int G_rle_expand(unsigned char *src, int src_sz, unsigned char *dst, int dst_sz)
Definition: cmprrle.c:141
char * dst
Definition: lz4.h:599