compress.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409
  1. /*
  2. ****************************************************************************
  3. * -- GRASS Development Team --
  4. *
  5. * MODULE: GRASS gis library
  6. * FILENAME: compress.c
  7. * AUTHOR(S): Markus Metz
  8. * PURPOSE: To provide an interface for compressing and
  9. * decompressing data using various methods. Its primary
  10. * use is in the storage and reading of GRASS rasters.
  11. *
  12. * DATE CREATED: Dec 17 2015
  13. * COPYRIGHT: (C) 2015 by the GRASS Development Team
  14. *
  15. * This program is free software under the GNU General Public
  16. * License (version 2 or greater). Read the file COPYING that
  17. * comes with GRASS for details.
  18. *
  19. *****************************************************************************/
  20. /********************************************************************
  21. * Compression methods: *
  22. * 1 : RLE (generic Run-Length Encoding of single bytes) *
  23. * 2 : ZLIB's DEFLATE (good speed and compression) *
  24. * 3 : LZ4 (fastest, low compression) *
  25. * 4 : BZIP2 (slowest, high compression) *
  26. * 5 : ZSTD (faster than ZLIB, higher compression than ZLIB) *
  27. * *
  28. * int *
  29. * G_read_compressed (fd, rbytes, dst, nbytes, compression_type) *
  30. * int fd, rbytes, nbytes; *
  31. * unsigned char *dst; *
  32. * ---------------------------------------------------------------- *
  33. * This is the basic function for reading a compressed chunk of a *
  34. * data file. The file descriptor should be in the proper location *
  35. * and the 'dst' array should have enough space for the data. *
  36. * 'nbytes' is the size of 'dst'. The 'rbytes' parameter is the *
  37. * number of bytes to read (knowable from the offsets index). For *
  38. * best results, 'nbytes' should be the exact amount of space *
  39. * needed for the expansion. Too large a value of nbytes may cause *
  40. * more data to be expanded than is desired. *
  41. * Returns: The number of bytes decompressed into dst, or an error. *
  42. * *
  43. * Errors include: *
  44. * -1 -- Error Reading or Decompressing data. *
  45. * -2 -- Not enough space in dst. You must make dst larger *
  46. * and then call the function again (remembering to *
  47. * reset the file descriptor to it's proper location. *
  48. * *
  49. * ================================================================ *
  50. * int *
  51. * G_write_compressed (fd, src, nbytes, compression_type) *
  52. * int fd, nbytes; *
  53. * unsigned char *src; *
  54. * ---------------------------------------------------------------- *
  55. * This is the basic function for writing and compressing a data *
  56. * chunk to a file. The file descriptor should be in the correct *
  57. * location prior to this call. The function will compress 'nbytes' *
  58. * of 'src' and write it to the file 'fd'. Returns the number of *
  59. * bytes written or an error code: *
  60. * *
  61. * Errors include: *
  62. * -1 -- Compression Failed. *
  63. * -2 -- Unable to write to file. *
  64. * *
  65. * ================================================================ *
  66. * int *
  67. * G_write_uncompressed (fd, src, nbytes) *
  68. * int fd, nbytes; *
  69. * unsigned char *src; *
  70. * ---------------------------------------------------------------- *
  71. * Works similar to G_write_compressed() except no attempt at *
  72. * compression is made. This is quicker, but may result in larger *
  73. * files. *
  74. * Returns the number of bytes written, or -1 for an error. It will *
  75. * return an error if it fails to write nbytes. Otherwise, the *
  76. * return value will always be nbytes + 1 (for compression flag). *
  77. * *
  78. ********************************************************************
  79. */
  80. #include <grass/config.h>
  81. #include <stdio.h>
  82. #include <stdlib.h>
  83. #include <string.h>
  84. #include <unistd.h>
  85. #include <grass/gis.h>
  86. #include <grass/glocale.h>
  87. #include "compress.h"
  88. #define G_COMPRESSED_NO (unsigned char)'0'
  89. #define G_COMPRESSED_YES (unsigned char)'1'
  90. /* get compressor number
  91. * return -1 on error
  92. * return number >= 0 for known processor */
  93. int G_compressor_number(char *name)
  94. {
  95. int i;
  96. if (!name)
  97. return -1;
  98. for (i = 0; compressor[i].name ; i++) {
  99. if (G_strcasecmp(name, compressor[i].name) == 0)
  100. return i;
  101. }
  102. return -1;
  103. }
  104. /* get compressor name
  105. * return NULL on error
  106. * return string (name) of known processor */
  107. char *G_compressor_name(int number)
  108. {
  109. if (number < 0 || number >= n_compressors)
  110. return NULL;
  111. return compressor[number].name;
  112. }
  113. int G_default_compressor(void)
  114. {
  115. #ifdef HAVE_ZSTD_H
  116. /* ZSTD */
  117. return 5;
  118. #endif
  119. /* ZLIB */
  120. return 2;
  121. }
  122. /* check compressor number
  123. * return -1 on error
  124. * return 0 known but not available
  125. * return 1 known and available */
  126. int G_check_compressor(int number)
  127. {
  128. if (number < 0 || number >= n_compressors) {
  129. G_warning(_("Request for unsupported compressor"));
  130. return -1;
  131. }
  132. return compressor[number].available;
  133. }
  134. int G_no_compress_bound(int src_sz)
  135. {
  136. return src_sz;
  137. }
  138. int
  139. G_no_compress(unsigned char *src, int src_sz, unsigned char *dst,
  140. int dst_sz)
  141. {
  142. /* Catch errors early */
  143. if (src == NULL || dst == NULL)
  144. return -1;
  145. /* Don't do anything if src is empty */
  146. if (src_sz <= 0)
  147. return 0;
  148. /* dst too small */
  149. if (dst_sz < src_sz)
  150. return -2;
  151. /* Copy the data from src to dst */
  152. memcpy(dst, src, src_sz);
  153. return src_sz;
  154. }
  155. int
  156. G_no_expand(unsigned char *src, int src_sz, unsigned char *dst,
  157. int dst_sz)
  158. {
  159. /* Catch errors early */
  160. if (src == NULL || dst == NULL)
  161. return -1;
  162. /* Don't do anything if src is empty */
  163. if (src_sz <= 0)
  164. return 0;
  165. /* dst too small */
  166. if (dst_sz < src_sz)
  167. return -2;
  168. /* Copy the data from src to dst */
  169. memcpy(dst, src, src_sz);
  170. return src_sz;
  171. }
  172. /* G_*_compress_bound() returns an upper bound on the compressed size
  173. * which can be larger than the input size
  174. * some compressors are a bit faster if the size of the destination
  175. * is at least the upper bound (no need to test for buffer overlflow)
  176. * read comments on the specific compressor interfaces
  177. */
  178. int G_compress_bound(int src_sz, int number)
  179. {
  180. if (number < 0 || number >= n_compressors) {
  181. G_fatal_error(_("Request for unsupported compressor"));
  182. return -1;
  183. }
  184. return compressor[number].bound(src_sz);
  185. }
  186. /* G_*_compress() returns
  187. * > 0: number of bytes in dst
  188. * 0: nothing done
  189. * -1: error
  190. * -2: dst too small
  191. */
  192. int
  193. G_compress(unsigned char *src, int src_sz, unsigned char *dst,
  194. int dst_sz, int number)
  195. {
  196. if (number < 0 || number >= n_compressors) {
  197. G_fatal_error(_("Request for unsupported compressor"));
  198. return -1;
  199. }
  200. return compressor[number].compress(src, src_sz, dst, dst_sz);
  201. }
  202. /* G_*_expand() returns
  203. * > 0: number of bytes in dst
  204. * -1: error
  205. */
  206. int
  207. G_expand(unsigned char *src, int src_sz, unsigned char *dst,
  208. int dst_sz, int number)
  209. {
  210. if (number < 0 || number >= n_compressors) {
  211. G_fatal_error(_("Request for unsupported compressor"));
  212. return -1;
  213. }
  214. return compressor[number].expand(src, src_sz, dst, dst_sz);
  215. }
  216. int G_read_compressed(int fd, int rbytes, unsigned char *dst, int nbytes,
  217. int number)
  218. {
  219. int bsize, nread, err;
  220. unsigned char *b;
  221. if (dst == NULL || nbytes < 0)
  222. return -2;
  223. bsize = rbytes;
  224. /* Our temporary input buffer for read */
  225. if (NULL == (b = (unsigned char *)
  226. G_calloc(bsize, sizeof(unsigned char))))
  227. return -1;
  228. /* Read from the file until we get our bsize or an error */
  229. nread = 0;
  230. do {
  231. err = read(fd, b + nread, bsize - nread);
  232. if (err >= 0)
  233. nread += err;
  234. } while (err > 0 && nread < bsize);
  235. /* If the bsize if less than rbytes and we didn't get an error.. */
  236. if (nread < rbytes && err > 0) {
  237. G_free(b);
  238. return -1;
  239. }
  240. /* Test if row is compressed */
  241. if (b[0] == G_COMPRESSED_NO) {
  242. /* Then just copy it to dst */
  243. for (err = 0; err < nread - 1 && err < nbytes; err++)
  244. dst[err] = b[err + 1];
  245. G_free(b);
  246. return (nread - 1);
  247. }
  248. else if (b[0] != G_COMPRESSED_YES) {
  249. /* We're not at the start of a row */
  250. G_free(b);
  251. return -1;
  252. }
  253. /* Okay it's a compressed row */
  254. /* Just call G_expand() with the buffer we read,
  255. * Account for first byte being a flag
  256. */
  257. err = G_expand(b + 1, bsize - 1, dst, nbytes, number);
  258. /* We're done with b */
  259. G_free(b);
  260. /* Return whatever G_expand() returned */
  261. return err;
  262. } /* G_read_compressed() */
  263. int G_write_compressed(int fd, unsigned char *src, int nbytes,
  264. int number)
  265. {
  266. int dst_sz, nwritten, err;
  267. unsigned char *dst, compressed;
  268. /* Catch errors */
  269. if (src == NULL || nbytes < 0)
  270. return -1;
  271. /* get upper bound of compressed size */
  272. dst_sz = G_compress_bound(nbytes, number);
  273. if (NULL == (dst = (unsigned char *)
  274. G_calloc(dst_sz, sizeof(unsigned char))))
  275. return -1;
  276. /* Now just call G_compress() */
  277. err = G_compress(src, nbytes, dst, dst_sz, number);
  278. /* If compression succeeded write compressed row,
  279. * otherwise write uncompressed row. Compression will fail
  280. * if dst is too small (i.e. compressed data is larger)
  281. */
  282. if (err > 0 && err < nbytes) {
  283. dst_sz = err;
  284. /* Write the compression flag */
  285. compressed = G_COMPRESSED_YES;
  286. if (write(fd, &compressed, 1) != 1) {
  287. G_free(dst);
  288. return -1;
  289. }
  290. nwritten = 0;
  291. do {
  292. err = write(fd, dst + nwritten, dst_sz - nwritten);
  293. if (err >= 0)
  294. nwritten += err;
  295. } while (err > 0 && nwritten < dst_sz);
  296. /* Account for extra byte */
  297. nwritten++;
  298. }
  299. else {
  300. /* Write compression flag */
  301. compressed = G_COMPRESSED_NO;
  302. if (write(fd, &compressed, 1) != 1) {
  303. G_free(dst);
  304. return -1;
  305. }
  306. nwritten = 0;
  307. do {
  308. err = write(fd, src + nwritten, nbytes - nwritten);
  309. if (err >= 0)
  310. nwritten += err;
  311. } while (err > 0 && nwritten < nbytes);
  312. /* Account for extra byte */
  313. nwritten++;
  314. } /* if (err > 0) */
  315. /* Done with the dst buffer */
  316. G_free(dst);
  317. /* If we didn't write all the data return an error */
  318. if (err < 0)
  319. return -2;
  320. return nwritten;
  321. } /* G_write_compressed() */
  322. int G_write_uncompressed(int fd, const unsigned char *src, int nbytes)
  323. {
  324. int err, nwritten;
  325. unsigned char compressed;
  326. /* Catch errors */
  327. if (src == NULL || nbytes < 0)
  328. return -1;
  329. /* Write the compression flag */
  330. compressed = G_COMPRESSED_NO;
  331. if (write(fd, &compressed, 1) != 1)
  332. return -1;
  333. /* Now write the data */
  334. nwritten = 0;
  335. do {
  336. err = write(fd, src + nwritten, nbytes - nwritten);
  337. if (err > 0)
  338. nwritten += err;
  339. } while (err > 0 && nwritten < nbytes);
  340. if (err < 0 || nwritten != nbytes)
  341. return -1;
  342. /* Account for extra compressed flag */
  343. nwritten++;
  344. /* That's all */
  345. return nwritten;
  346. } /* G_write_uncompressed() */
  347. /* vim: set softtabstop=4 shiftwidth=4 expandtab: */