GRASS GIS 8 Programmer's Manual 8.3.2(2024)-exported
Loading...
Searching...
No Matches
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 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
139int 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