cmprrle.c 6.0 KB

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