compress.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  1. /* compress.c
  2. *
  3. * Copyright (C) 2006-2023 wolfSSL Inc.
  4. *
  5. * This file is part of wolfSSL.
  6. *
  7. * wolfSSL is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * wolfSSL is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
  20. */
  21. #ifdef HAVE_CONFIG_H
  22. #include <config.h>
  23. #endif
  24. #include <wolfssl/wolfcrypt/settings.h>
  25. #ifdef HAVE_LIBZ
  26. #include <wolfssl/wolfcrypt/compress.h>
  27. #include <wolfssl/wolfcrypt/error-crypt.h>
  28. #include <wolfssl/wolfcrypt/logging.h>
  29. #ifdef NO_INLINE
  30. #include <wolfssl/wolfcrypt/misc.h>
  31. #else
  32. #define WOLFSSL_MISC_INCLUDED
  33. #include <wolfcrypt/src/misc.c>
  34. #endif
  35. #include <zlib.h>
  36. /* alloc user allocs to work with zlib */
  37. static void* myAlloc(void* opaque, unsigned int item, unsigned int size)
  38. {
  39. (void)opaque;
  40. return (void *)XMALLOC(item * size, opaque, DYNAMIC_TYPE_LIBZ);
  41. }
  42. static void myFree(void* opaque, void* memory)
  43. {
  44. (void)opaque;
  45. XFREE(memory, opaque, DYNAMIC_TYPE_LIBZ);
  46. }
  47. #ifdef HAVE_MCAPI
  48. #define DEFLATE_DEFAULT_WINDOWBITS 11
  49. #define DEFLATE_DEFAULT_MEMLEVEL 1
  50. #else
  51. #define DEFLATE_DEFAULT_WINDOWBITS 15
  52. #define DEFLATE_DEFAULT_MEMLEVEL 8
  53. #endif
  54. /*
  55. * out - pointer to destination buffer
  56. * outSz - size of destination buffer
  57. * in - pointer to source buffer to compress
  58. * inSz - size of source to compress
  59. * flags - flags to control how compress operates
  60. *
  61. * return:
  62. * negative - error code
  63. * positive - bytes stored in out buffer
  64. *
  65. * Note, the output buffer still needs to be larger than the input buffer.
  66. * The right chunk of data won't compress at all, and the lookup table will
  67. * add to the size of the output. The libz code says the compressed
  68. * buffer should be srcSz + 0.1% + 12.
  69. */
  70. int wc_Compress_ex(byte* out, word32 outSz, const byte* in, word32 inSz,
  71. word32 flags, word32 windowBits)
  72. {
  73. z_stream stream;
  74. int result = 0;
  75. stream.next_in = (Bytef*)in;
  76. stream.avail_in = (uInt)inSz;
  77. #ifdef MAXSEG_64K
  78. /* Check for source > 64K on 16-bit machine: */
  79. if ((uLong)stream.avail_in != inSz) return COMPRESS_INIT_E;
  80. #endif
  81. stream.next_out = out;
  82. stream.avail_out = (uInt)outSz;
  83. if ((uLong)stream.avail_out != outSz) return COMPRESS_INIT_E;
  84. stream.zalloc = (alloc_func)myAlloc;
  85. stream.zfree = (free_func)myFree;
  86. stream.opaque = (voidpf)0;
  87. if (deflateInit2(&stream, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
  88. DEFLATE_DEFAULT_WINDOWBITS | windowBits,
  89. DEFLATE_DEFAULT_MEMLEVEL,
  90. flags ? Z_FIXED : Z_DEFAULT_STRATEGY) != Z_OK)
  91. return COMPRESS_INIT_E;
  92. if (deflate(&stream, Z_FINISH) != Z_STREAM_END) {
  93. deflateEnd(&stream);
  94. return COMPRESS_E;
  95. }
  96. result = (int)stream.total_out;
  97. if (deflateEnd(&stream) != Z_OK)
  98. result = COMPRESS_E;
  99. return result;
  100. }
  101. int wc_Compress(byte* out, word32 outSz, const byte* in, word32 inSz, word32 flags)
  102. {
  103. return wc_Compress_ex(out, outSz, in, inSz, flags, 0);
  104. }
  105. /* windowBits:
  106. * deflateInit() and inflateInit(), as well as deflateInit2() and inflateInit2()
  107. with windowBits in 0..15 all process zlib-wrapped deflate data.
  108. (See RFC 1950 and RFC 1951.)
  109. * deflateInit2() and inflateInit2() with negative windowBits in -1..-15 process
  110. raw deflate data with no header or trailer.
  111. * deflateInit2() and inflateInit2() with windowBits in 16..31, i.e. 16
  112. added to 0..15, process gzip-wrapped deflate data (RFC 1952).
  113. * inflateInit2() with windowBits in 32..47 (32 added to 0..15) will
  114. automatically detect either a gzip or zlib header (but not raw deflate
  115. data), and decompress accordingly.
  116. */
  117. int wc_DeCompress_ex(byte* out, word32 outSz, const byte* in, word32 inSz,
  118. int windowBits)
  119. /*
  120. * out - pointer to destination buffer
  121. * outSz - size of destination buffer
  122. * in - pointer to source buffer to compress
  123. * inSz - size of source to compress
  124. * windowBits - flags to control how decompress operates
  125. *
  126. * return:
  127. * negative - error code
  128. * positive - bytes stored in out buffer
  129. */
  130. {
  131. z_stream stream;
  132. int result = 0;
  133. stream.next_in = (Bytef*)in;
  134. stream.avail_in = (uInt)inSz;
  135. /* Check for source > 64K on 16-bit machine: */
  136. if ((uLong)stream.avail_in != inSz) return DECOMPRESS_INIT_E;
  137. stream.next_out = out;
  138. stream.avail_out = (uInt)outSz;
  139. if ((uLong)stream.avail_out != outSz) return DECOMPRESS_INIT_E;
  140. stream.zalloc = (alloc_func)myAlloc;
  141. stream.zfree = (free_func)myFree;
  142. stream.opaque = (voidpf)0;
  143. if (inflateInit2(&stream, DEFLATE_DEFAULT_WINDOWBITS | windowBits) != Z_OK)
  144. return DECOMPRESS_INIT_E;
  145. result = inflate(&stream, Z_FINISH);
  146. if (result != Z_STREAM_END) {
  147. inflateEnd(&stream);
  148. return DECOMPRESS_E;
  149. }
  150. result = (int)stream.total_out;
  151. if (inflateEnd(&stream) != Z_OK)
  152. result = DECOMPRESS_E;
  153. return result;
  154. }
  155. int wc_DeCompress(byte* out, word32 outSz, const byte* in, word32 inSz)
  156. {
  157. return wc_DeCompress_ex(out, outSz, in, inSz, 0);
  158. }
  159. /* Decompress the input buffer and create output buffer. Free'ing 'out' buffer
  160. * is the callers responsibility on successful return.
  161. *
  162. * out gets set to the output buffer created, *out gets overwritten
  163. * maxSz is the max decompression multiplier, i.e if 2 then max out size created
  164. * would be 2*inSz, if set to -1 then there is no limit on out buffer size
  165. * memoryType the memory hint to use for 'out' i.e. DYNAMIC_TYPE_TMP_BUFFER
  166. * in compressed input buffer
  167. * inSz size of 'in' buffer
  168. * windowBits decompression behavior flag (can be 0)
  169. * heap hint to use when mallocing 'out' buffer
  170. *
  171. * return the decompressed size, creates and grows out buffer as needed
  172. */
  173. int wc_DeCompressDynamic(byte** out, int maxSz, int memoryType,
  174. const byte* in, word32 inSz, int windowBits, void* heap)
  175. {
  176. z_stream stream;
  177. int result = 0;
  178. int i;
  179. word32 tmpSz = 0;
  180. byte* tmp;
  181. (void)memoryType;
  182. (void)heap;
  183. if (out == NULL || in == NULL) {
  184. return BAD_FUNC_ARG;
  185. }
  186. i = (maxSz == 1)? 1 : 2; /* start with output buffer twice the size of input
  187. * unless max was set to 1 */
  188. stream.next_in = (Bytef*)in;
  189. stream.avail_in = (uInt)inSz;
  190. /* Check for source > 64K on 16-bit machine: */
  191. if ((uLong)stream.avail_in != inSz) return DECOMPRESS_INIT_E;
  192. tmpSz = inSz * i;
  193. tmp = (byte*)XMALLOC(tmpSz, heap, memoryType);
  194. if (tmp == NULL)
  195. return MEMORY_E;
  196. stream.next_out = tmp;
  197. stream.avail_out = (uInt)tmpSz;
  198. if ((uLong)stream.avail_out != tmpSz) return DECOMPRESS_INIT_E;
  199. stream.zalloc = (alloc_func)myAlloc;
  200. stream.zfree = (free_func)myFree;
  201. stream.opaque = (voidpf)0;
  202. if (inflateInit2(&stream, DEFLATE_DEFAULT_WINDOWBITS | windowBits) != Z_OK) {
  203. XFREE(tmp, heap, memoryType);
  204. return DECOMPRESS_INIT_E;
  205. }
  206. /*
  207. Wanted to use inflateGetHeader here for uncompressed size but
  208. structure gz_headerp does not contain the ISIZE from RFC1952
  209. gz_headerp header;
  210. inflateGetHeader(&stream, &header);
  211. */
  212. /* loop through doing the decompression block by block to get full size */
  213. do {
  214. result = inflate(&stream, Z_BLOCK);
  215. if (result == Z_STREAM_END) {
  216. /* hit end of decompression */
  217. break;
  218. }
  219. /* good chance output buffer ran out of space with Z_BUF_ERROR
  220. try increasing output buffer size */
  221. if (result == Z_BUF_ERROR) {
  222. word32 newSz;
  223. byte* newTmp;
  224. if (maxSz > 0 && i >= maxSz) {
  225. WOLFSSL_MSG("Hit max decompress size!");
  226. break;
  227. }
  228. i++;
  229. newSz = tmpSz + inSz;
  230. newTmp = (byte*)XMALLOC(newSz, heap, memoryType);
  231. if (newTmp == NULL) {
  232. WOLFSSL_MSG("Memory error with increasing buffer size");
  233. break;
  234. }
  235. XMEMCPY(newTmp, tmp, tmpSz);
  236. XFREE(tmp, heap, memoryType);
  237. tmp = newTmp;
  238. stream.next_out = tmp + stream.total_out;
  239. stream.avail_out = stream.avail_out + (uInt)inSz;
  240. tmpSz = newSz;
  241. result = inflate(&stream, Z_BLOCK);
  242. }
  243. } while (result == Z_OK);
  244. if (result == Z_STREAM_END) {
  245. result = (int)stream.total_out;
  246. *out = (byte*)XMALLOC(result, heap, memoryType);
  247. if (*out != NULL) {
  248. XMEMCPY(*out, tmp, result);
  249. }
  250. else {
  251. result = MEMORY_E;
  252. }
  253. }
  254. else {
  255. result = DECOMPRESS_E;
  256. }
  257. if (inflateEnd(&stream) != Z_OK)
  258. result = DECOMPRESS_E;
  259. if (tmp != NULL) {
  260. XFREE(tmp, heap, memoryType);
  261. tmp = NULL;
  262. }
  263. return result;
  264. }
  265. #endif /* HAVE_LIBZ */