123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198 |
- /*
- ****************************************************************************
- * -- GRASS Development Team --
- *
- * MODULE: GRASS gis library
- * FILENAME: cmprrle.c
- * AUTHOR(S): Markus Metz
- * PURPOSE: To provide generic RLE for compressing and
- * decompressing data. Its primary use is in
- * the storage and reading of GRASS rasters.
- *
- * ALGORITHM: Run Length Encoding
- * DATE CREATED: Dec 18 2015
- * COPYRIGHT: (C) 2015 by the GRASS Development Team
- *
- * This program is free software under the GNU General Public
- * License (version 2 or greater). Read the file COPYING that
- * comes with GRASS for details.
- *
- *****************************************************************************/
- /********************************************************************
- * int *
- * G_rle_compress (src, srz_sz, dst, dst_sz) *
- * int src_sz, dst_sz; *
- * unsigned char *src, *dst; *
- * ---------------------------------------------------------------- *
- * This function compresses data with RLE. *
- * It uses an all or nothing call. *
- * If you need a continuous compression scheme, you'll have to code *
- * your own. *
- * *
- * The function either returns the number of bytes of compressed *
- * data in dst, or an error code. *
- * *
- * Errors include: *
- * -1 -- Compression failed. *
- * -2 -- dst is too small. *
- * *
- * ================================================================ *
- * int *
- * G_rle_expand (src, src_sz, dst, dst_sz) *
- * int src_sz, dst_sz; *
- * unsigned char *src, *dst; *
- * ---------------------------------------------------------------- *
- * This function decompresses data compressed with RLE. *
- * It is equivalent to a single pass call to an external expansion *
- * function. *
- * If you need a continuous expansion scheme, you'll have to code *
- * your own. *
- * *
- * The function returns the number of bytes expanded into 'dst' or *
- * and error code. *
- * *
- * Errors include: *
- * -1 -- Expansion failed. *
- * *
- ********************************************************************
- */
- #include <grass/config.h>
- #include <grass/gis.h>
- #include <grass/glocale.h>
- /* no fast mode if destination is large enough to hold
- * worst case compression */
- int G_rle_compress_bound(int src_sz)
- {
- return ((src_sz >> 1) * 3 + (src_sz & 1));
- }
- int
- G_rle_compress(unsigned char *src, int src_sz, unsigned char *dst,
- int dst_sz)
- {
- int i, nbytes;
- unsigned char prev_b;
- int cnt;
- /* Catch errors early */
- if (src == NULL || dst == NULL)
- return -1;
- /* Don't do anything if src is empty or smaller than 4 bytes */
- if (src_sz <= 3)
- return 0;
- /* modified RLE:
- * unit is 1 byte, only sequences longer than 1 are encoded
- * single occurrences don't have a following count
- * multiple occurrences are twice in dst, followed by the count
- * example:
- * ABBCCC
- * is encoded as
- * ABB2CC3
- */
-
- prev_b = src[0];
- cnt = 1;
- nbytes = 0;
- for (i = 1; i < src_sz; i++) {
- if (prev_b != src[i] || cnt == 255) {
- /* write to dst */
- if (cnt == 1) {
- if (nbytes >= dst_sz)
- return -2;
- dst[nbytes++] = prev_b;
- }
- else {
- /* cnt > 1 */
- if (nbytes >= dst_sz - 2)
- return -2;
- dst[nbytes++] = prev_b;
- dst[nbytes++] = prev_b;
- dst[nbytes++] = (unsigned char) cnt;
- }
- cnt = 0;
- }
- prev_b = src[i];
- cnt++;
- }
- /* write out the last sequence */
- if (cnt == 1) {
- if (nbytes >= dst_sz)
- return -2;
- dst[nbytes++] = prev_b;
- }
- else {
- if (nbytes >= dst_sz - 2)
- return -2;
- dst[nbytes++] = prev_b;
- dst[nbytes++] = prev_b;
- dst[nbytes++] = (unsigned char) cnt;
- }
- return nbytes;
- }
- int
- G_rle_expand(unsigned char *src, int src_sz, unsigned char *dst,
- int dst_sz)
- {
- int i, j, nbytes, cnt;
- unsigned char prev_b;
- /* Catch errors early */
- if (src == NULL || dst == NULL)
- return -1;
- /* Don't do anything if src is empty */
- if (src_sz <= 0)
- return 0;
- /* RLE expand */
- prev_b = src[0];
- cnt = 1;
- nbytes = 0;
- i = 1;
- while (i < src_sz) {
- /* single occurrences don't have a following count
- * multiple occurrences are twice in src, followed by the count */
- if (cnt == 2) {
- if (i >= src_sz)
- return -1;
- cnt = src[i];
- if (nbytes + cnt > dst_sz)
- return -1;
- for (j = 0; j < cnt; j++) {
- dst[nbytes++] = prev_b;
- }
- cnt = 0;
- i++;
- if (i >= src_sz)
- return nbytes;
- }
- if (cnt == 1) {
- if (prev_b != src[i]) {
- if (nbytes + cnt > dst_sz)
- return -1;
- dst[nbytes++] = prev_b;
- cnt = 0;
- }
- }
- prev_b = src[i];
- cnt++;
- i++;
- }
- if (nbytes >= dst_sz)
- return -1;
- if (cnt == 1)
- dst[nbytes++] = prev_b;
- return nbytes;
- }
- /* vim: set softtabstop=4 shiftwidth=4 expandtab: */
|