lzham_lzcomp.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608
  1. // File: lzham_lzcomp.cpp
  2. // See Copyright Notice and license at the end of include/lzham.h
  3. #include "lzham_core.h"
  4. #include "lzham.h"
  5. #include "lzham_comp.h"
  6. #include "lzham_lzcomp_internal.h"
  7. using namespace lzham;
  8. namespace lzham
  9. {
  10. struct lzham_compress_state
  11. {
  12. // task_pool requires 8 or 16 alignment
  13. task_pool m_tp;
  14. lzcompressor m_compressor;
  15. uint m_dict_size_log2;
  16. const uint8 *m_pIn_buf;
  17. size_t *m_pIn_buf_size;
  18. uint8 *m_pOut_buf;
  19. size_t *m_pOut_buf_size;
  20. size_t m_comp_data_ofs;
  21. bool m_finished_compression;
  22. lzham_compress_params m_params;
  23. lzham_compress_status_t m_status;
  24. };
  25. static lzham_compress_status_t create_internal_init_params(lzcompressor::init_params &internal_params, const lzham_compress_params *pParams)
  26. {
  27. if ((pParams->m_dict_size_log2 < CLZBase::cMinDictSizeLog2) || (pParams->m_dict_size_log2 > CLZBase::cMaxDictSizeLog2))
  28. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  29. internal_params.m_dict_size_log2 = pParams->m_dict_size_log2;
  30. if (pParams->m_max_helper_threads < 0)
  31. internal_params.m_max_helper_threads = lzham_get_max_helper_threads();
  32. else
  33. internal_params.m_max_helper_threads = pParams->m_max_helper_threads;
  34. internal_params.m_max_helper_threads = LZHAM_MIN(LZHAM_MAX_HELPER_THREADS, internal_params.m_max_helper_threads);
  35. internal_params.m_lzham_compress_flags = pParams->m_compress_flags;
  36. if (pParams->m_num_seed_bytes)
  37. {
  38. if ((!pParams->m_pSeed_bytes) || (pParams->m_num_seed_bytes > (1U << pParams->m_dict_size_log2)))
  39. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  40. internal_params.m_num_seed_bytes = pParams->m_num_seed_bytes;
  41. internal_params.m_pSeed_bytes = pParams->m_pSeed_bytes;
  42. }
  43. switch (pParams->m_level)
  44. {
  45. case LZHAM_COMP_LEVEL_FASTEST: internal_params.m_compression_level = cCompressionLevelFastest; break;
  46. case LZHAM_COMP_LEVEL_FASTER: internal_params.m_compression_level = cCompressionLevelFaster; break;
  47. case LZHAM_COMP_LEVEL_DEFAULT: internal_params.m_compression_level = cCompressionLevelDefault; break;
  48. case LZHAM_COMP_LEVEL_BETTER: internal_params.m_compression_level = cCompressionLevelBetter; break;
  49. case LZHAM_COMP_LEVEL_UBER: internal_params.m_compression_level = cCompressionLevelUber; break;
  50. default:
  51. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  52. };
  53. if (pParams->m_table_max_update_interval || pParams->m_table_update_interval_slow_rate)
  54. {
  55. internal_params.m_table_max_update_interval = pParams->m_table_max_update_interval;
  56. internal_params.m_table_update_interval_slow_rate = pParams->m_table_update_interval_slow_rate;
  57. }
  58. else
  59. {
  60. uint rate = pParams->m_table_update_rate;
  61. if (!rate)
  62. rate = LZHAM_DEFAULT_TABLE_UPDATE_RATE;
  63. rate = math::clamp<uint>(rate, 1, LZHAM_FASTEST_TABLE_UPDATE_RATE) - 1;
  64. internal_params.m_table_max_update_interval = g_table_update_settings[rate].m_max_update_interval;
  65. internal_params.m_table_update_interval_slow_rate = g_table_update_settings[rate].m_slow_rate;
  66. }
  67. return LZHAM_COMP_STATUS_SUCCESS;
  68. }
  69. lzham_compress_state_ptr LZHAM_CDECL lzham_lib_compress_init(const lzham_compress_params *pParams)
  70. {
  71. if ((!pParams) || (pParams->m_struct_size != sizeof(lzham_compress_params)))
  72. return NULL;
  73. if ((pParams->m_dict_size_log2 < CLZBase::cMinDictSizeLog2) || (pParams->m_dict_size_log2 > CLZBase::cMaxDictSizeLog2))
  74. return NULL;
  75. lzcompressor::init_params internal_params;
  76. lzham_compress_status_t status = create_internal_init_params(internal_params, pParams);
  77. if (status != LZHAM_COMP_STATUS_SUCCESS)
  78. return NULL;
  79. lzham_compress_state *pState = lzham_new<lzham_compress_state>();
  80. if (!pState)
  81. return NULL;
  82. pState->m_params = *pParams;
  83. pState->m_pIn_buf = NULL;
  84. pState->m_pIn_buf_size = NULL;
  85. pState->m_pOut_buf = NULL;
  86. pState->m_pOut_buf_size = NULL;
  87. pState->m_status = LZHAM_COMP_STATUS_NOT_FINISHED;
  88. pState->m_comp_data_ofs = 0;
  89. pState->m_finished_compression = false;
  90. if (internal_params.m_max_helper_threads)
  91. {
  92. if (!pState->m_tp.init(internal_params.m_max_helper_threads))
  93. {
  94. lzham_delete(pState);
  95. return NULL;
  96. }
  97. if (pState->m_tp.get_num_threads() >= internal_params.m_max_helper_threads)
  98. {
  99. internal_params.m_pTask_pool = &pState->m_tp;
  100. }
  101. else
  102. {
  103. internal_params.m_max_helper_threads = 0;
  104. }
  105. }
  106. if (!pState->m_compressor.init(internal_params))
  107. {
  108. lzham_delete(pState);
  109. return NULL;
  110. }
  111. return pState;
  112. }
  113. lzham_compress_state_ptr LZHAM_CDECL lzham_lib_compress_reinit(lzham_compress_state_ptr p)
  114. {
  115. lzham_compress_state *pState = static_cast<lzham_compress_state*>(p);
  116. if (pState)
  117. {
  118. if (!pState->m_compressor.reset())
  119. return NULL;
  120. pState->m_pIn_buf = NULL;
  121. pState->m_pIn_buf_size = NULL;
  122. pState->m_pOut_buf = NULL;
  123. pState->m_pOut_buf_size = NULL;
  124. pState->m_status = LZHAM_COMP_STATUS_NOT_FINISHED;
  125. pState->m_comp_data_ofs = 0;
  126. pState->m_finished_compression = false;
  127. }
  128. return pState;
  129. }
  130. lzham_uint32 LZHAM_CDECL lzham_lib_compress_deinit(lzham_compress_state_ptr p)
  131. {
  132. lzham_compress_state *pState = static_cast<lzham_compress_state *>(p);
  133. if (!pState)
  134. return 0;
  135. uint32 adler32 = pState->m_compressor.get_src_adler32();
  136. lzham_delete(pState);
  137. return adler32;
  138. }
  139. lzham_compress_status_t LZHAM_CDECL lzham_lib_compress(
  140. lzham_compress_state_ptr p,
  141. const lzham_uint8 *pIn_buf, size_t *pIn_buf_size,
  142. lzham_uint8 *pOut_buf, size_t *pOut_buf_size,
  143. lzham_bool no_more_input_bytes_flag)
  144. {
  145. return lzham_lib_compress2(p, pIn_buf, pIn_buf_size, pOut_buf, pOut_buf_size, no_more_input_bytes_flag ? LZHAM_FINISH : LZHAM_NO_FLUSH);
  146. }
  147. lzham_compress_status_t LZHAM_CDECL lzham_lib_compress2(
  148. lzham_compress_state_ptr p,
  149. const lzham_uint8 *pIn_buf, size_t *pIn_buf_size,
  150. lzham_uint8 *pOut_buf, size_t *pOut_buf_size,
  151. lzham_flush_t flush_type)
  152. {
  153. lzham_compress_state *pState = static_cast<lzham_compress_state*>(p);
  154. if ((!pState) || (!pState->m_params.m_dict_size_log2) || (pState->m_status >= LZHAM_COMP_STATUS_FIRST_SUCCESS_OR_FAILURE_CODE) || (!pIn_buf_size) || (!pOut_buf_size))
  155. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  156. if ((*pIn_buf_size) && (!pIn_buf))
  157. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  158. if ((!*pOut_buf_size) || (!pOut_buf))
  159. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  160. byte_vec &comp_data = pState->m_compressor.get_compressed_data();
  161. size_t num_bytes_written_to_out_buf = 0;
  162. if (pState->m_comp_data_ofs < comp_data.size())
  163. {
  164. size_t n = LZHAM_MIN(comp_data.size() - pState->m_comp_data_ofs, *pOut_buf_size);
  165. memcpy(pOut_buf, comp_data.get_ptr() + pState->m_comp_data_ofs, n);
  166. pState->m_comp_data_ofs += n;
  167. const bool has_no_more_output = (pState->m_comp_data_ofs >= comp_data.size());
  168. if (has_no_more_output)
  169. {
  170. pOut_buf += n;
  171. *pOut_buf_size -= n;
  172. num_bytes_written_to_out_buf += n;
  173. }
  174. else
  175. {
  176. *pIn_buf_size = 0;
  177. *pOut_buf_size = n;
  178. pState->m_status = LZHAM_COMP_STATUS_HAS_MORE_OUTPUT;
  179. return pState->m_status;
  180. }
  181. }
  182. comp_data.try_resize(0);
  183. pState->m_comp_data_ofs = 0;
  184. if (pState->m_finished_compression)
  185. {
  186. if ((*pIn_buf_size) || (flush_type != LZHAM_FINISH))
  187. {
  188. pState->m_status = LZHAM_COMP_STATUS_INVALID_PARAMETER;
  189. return pState->m_status;
  190. }
  191. *pIn_buf_size = 0;
  192. *pOut_buf_size = num_bytes_written_to_out_buf;
  193. pState->m_status = LZHAM_COMP_STATUS_SUCCESS;
  194. return pState->m_status;
  195. }
  196. const size_t cMaxBytesToPutPerIteration = 4*1024*1024;
  197. size_t bytes_to_put = LZHAM_MIN(cMaxBytesToPutPerIteration, *pIn_buf_size);
  198. const bool consumed_entire_input_buf = (bytes_to_put == *pIn_buf_size);
  199. if (bytes_to_put)
  200. {
  201. if (!pState->m_compressor.put_bytes(pIn_buf, (uint)bytes_to_put))
  202. {
  203. *pIn_buf_size = 0;
  204. *pOut_buf_size = num_bytes_written_to_out_buf;
  205. pState->m_status = LZHAM_COMP_STATUS_FAILED;
  206. return pState->m_status;
  207. }
  208. }
  209. if ((consumed_entire_input_buf) && (flush_type != LZHAM_NO_FLUSH))
  210. {
  211. if ((flush_type == LZHAM_SYNC_FLUSH) || (flush_type == LZHAM_FULL_FLUSH) || (flush_type == LZHAM_TABLE_FLUSH))
  212. {
  213. if (!pState->m_compressor.flush(flush_type))
  214. {
  215. *pIn_buf_size = 0;
  216. *pOut_buf_size = num_bytes_written_to_out_buf;
  217. pState->m_status = LZHAM_COMP_STATUS_FAILED;
  218. return pState->m_status;
  219. }
  220. }
  221. else if (!pState->m_finished_compression)
  222. {
  223. if (!pState->m_compressor.put_bytes(NULL, 0))
  224. {
  225. *pIn_buf_size = 0;
  226. *pOut_buf_size = num_bytes_written_to_out_buf;
  227. pState->m_status = LZHAM_COMP_STATUS_FAILED;
  228. return pState->m_status;
  229. }
  230. pState->m_finished_compression = true;
  231. }
  232. }
  233. size_t num_comp_bytes_to_output = LZHAM_MIN(comp_data.size() - pState->m_comp_data_ofs, *pOut_buf_size);
  234. if (num_comp_bytes_to_output)
  235. {
  236. memcpy(pOut_buf, comp_data.get_ptr() + pState->m_comp_data_ofs, num_comp_bytes_to_output);
  237. pState->m_comp_data_ofs += num_comp_bytes_to_output;
  238. }
  239. *pIn_buf_size = bytes_to_put;
  240. *pOut_buf_size = num_bytes_written_to_out_buf + num_comp_bytes_to_output;
  241. const bool has_no_more_output = (pState->m_comp_data_ofs >= comp_data.size());
  242. if ((has_no_more_output) && (flush_type == LZHAM_FINISH) && (pState->m_finished_compression))
  243. pState->m_status = LZHAM_COMP_STATUS_SUCCESS;
  244. else if ((has_no_more_output) && (consumed_entire_input_buf) && (flush_type == LZHAM_NO_FLUSH))
  245. pState->m_status = LZHAM_COMP_STATUS_NEEDS_MORE_INPUT;
  246. else
  247. pState->m_status = has_no_more_output ? LZHAM_COMP_STATUS_NOT_FINISHED : LZHAM_COMP_STATUS_HAS_MORE_OUTPUT;
  248. return pState->m_status;
  249. }
  250. lzham_compress_status_t LZHAM_CDECL lzham_lib_compress_memory(const lzham_compress_params *pParams, lzham_uint8* pDst_buf, size_t *pDst_len, const lzham_uint8* pSrc_buf, size_t src_len, lzham_uint32 *pAdler32)
  251. {
  252. if ((!pParams) || (!pDst_len))
  253. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  254. if (src_len)
  255. {
  256. if (!pSrc_buf)
  257. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  258. }
  259. if (sizeof(size_t) > sizeof(uint32))
  260. {
  261. if (src_len > UINT32_MAX)
  262. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  263. }
  264. lzcompressor::init_params internal_params;
  265. lzham_compress_status_t status = create_internal_init_params(internal_params, pParams);
  266. if (status != LZHAM_COMP_STATUS_SUCCESS)
  267. return status;
  268. task_pool *pTP = NULL;
  269. if (internal_params.m_max_helper_threads)
  270. {
  271. pTP = lzham_new<task_pool>();
  272. if (!pTP->init(internal_params.m_max_helper_threads))
  273. return LZHAM_COMP_STATUS_FAILED;
  274. internal_params.m_pTask_pool = pTP;
  275. }
  276. lzcompressor *pCompressor = lzham_new<lzcompressor>();
  277. if (!pCompressor)
  278. {
  279. lzham_delete(pTP);
  280. return LZHAM_COMP_STATUS_FAILED;
  281. }
  282. if (!pCompressor->init(internal_params))
  283. {
  284. lzham_delete(pTP);
  285. lzham_delete(pCompressor);
  286. return LZHAM_COMP_STATUS_INVALID_PARAMETER;
  287. }
  288. if (src_len)
  289. {
  290. if (!pCompressor->put_bytes(pSrc_buf, static_cast<uint32>(src_len)))
  291. {
  292. *pDst_len = 0;
  293. lzham_delete(pTP);
  294. lzham_delete(pCompressor);
  295. return LZHAM_COMP_STATUS_FAILED;
  296. }
  297. }
  298. if (!pCompressor->put_bytes(NULL, 0))
  299. {
  300. *pDst_len = 0;
  301. lzham_delete(pTP);
  302. lzham_delete(pCompressor);
  303. return LZHAM_COMP_STATUS_FAILED;
  304. }
  305. const byte_vec &comp_data = pCompressor->get_compressed_data();
  306. size_t dst_buf_size = *pDst_len;
  307. *pDst_len = comp_data.size();
  308. if (pAdler32)
  309. *pAdler32 = pCompressor->get_src_adler32();
  310. if (comp_data.size() > dst_buf_size)
  311. {
  312. lzham_delete(pTP);
  313. lzham_delete(pCompressor);
  314. return LZHAM_COMP_STATUS_OUTPUT_BUF_TOO_SMALL;
  315. }
  316. memcpy(pDst_buf, comp_data.get_ptr(), comp_data.size());
  317. lzham_delete(pTP);
  318. lzham_delete(pCompressor);
  319. return LZHAM_COMP_STATUS_SUCCESS;
  320. }
  321. // ----------------- zlib-style API's
  322. int lzham_lib_z_deflateInit(lzham_z_streamp pStream, int level)
  323. {
  324. return lzham_lib_z_deflateInit2(pStream, level, LZHAM_Z_LZHAM, LZHAM_Z_DEFAULT_WINDOW_BITS, 9, LZHAM_Z_DEFAULT_STRATEGY);
  325. }
  326. int lzham_lib_z_deflateInit2(lzham_z_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
  327. {
  328. LZHAM_NOTE_UNUSED(strategy);
  329. if (!pStream)
  330. return LZHAM_Z_STREAM_ERROR;
  331. if ((mem_level < 1) || (mem_level > 9))
  332. return LZHAM_Z_PARAM_ERROR;
  333. if ((method != LZHAM_Z_DEFLATED) && (method != LZHAM_Z_LZHAM))
  334. return LZHAM_Z_PARAM_ERROR;
  335. if (level == LZHAM_Z_DEFAULT_COMPRESSION)
  336. level = 9;
  337. if (method == LZHAM_Z_DEFLATED)
  338. {
  339. // Force Deflate to LZHAM with default window_bits.
  340. method = LZHAM_Z_LZHAM;
  341. window_bits = LZHAM_Z_DEFAULT_WINDOW_BITS;
  342. }
  343. #ifdef LZHAM_Z_API_FORCE_WINDOW_BITS
  344. window_bits = LZHAM_Z_API_FORCE_WINDOW_BITS;
  345. #endif
  346. int max_window_bits = LZHAM_64BIT_POINTERS ? LZHAM_MAX_DICT_SIZE_LOG2_X64 : LZHAM_MAX_DICT_SIZE_LOG2_X86;
  347. if ((labs(window_bits) < LZHAM_MIN_DICT_SIZE_LOG2) || (labs(window_bits) > max_window_bits))
  348. return LZHAM_Z_PARAM_ERROR;
  349. lzham_compress_params comp_params;
  350. utils::zero_object(comp_params);
  351. comp_params.m_struct_size = sizeof(lzham_compress_params);
  352. comp_params.m_level = LZHAM_COMP_LEVEL_UBER;
  353. if (level <= 1)
  354. comp_params.m_level = LZHAM_COMP_LEVEL_FASTEST;
  355. else if (level <= 3)
  356. comp_params.m_level = LZHAM_COMP_LEVEL_FASTER;
  357. else if (level <= 5)
  358. comp_params.m_level = LZHAM_COMP_LEVEL_DEFAULT;
  359. else if (level <= 7)
  360. comp_params.m_level = LZHAM_COMP_LEVEL_BETTER;
  361. if (level == 10)
  362. comp_params.m_compress_flags |= LZHAM_COMP_FLAG_EXTREME_PARSING;
  363. // Use all CPU's. TODO: This is not always the best idea depending on the dictionary size and the # of bytes to compress.
  364. comp_params.m_max_helper_threads = -1;
  365. comp_params.m_dict_size_log2 = static_cast<lzham_uint32>(labs(window_bits));
  366. if (window_bits > 0)
  367. comp_params.m_compress_flags |= LZHAM_COMP_FLAG_WRITE_ZLIB_STREAM;
  368. pStream->data_type = 0;
  369. pStream->adler = LZHAM_Z_ADLER32_INIT;
  370. pStream->msg = NULL;
  371. pStream->reserved = 0;
  372. pStream->total_in = 0;
  373. pStream->total_out = 0;
  374. lzham_compress_state_ptr pComp = lzham_lib_compress_init(&comp_params);
  375. if (!pComp)
  376. return LZHAM_Z_PARAM_ERROR;
  377. pStream->state = (struct lzham_z_internal_state *)pComp;
  378. return LZHAM_Z_OK;
  379. }
  380. int lzham_lib_z_deflateReset(lzham_z_streamp pStream)
  381. {
  382. if (!pStream)
  383. return LZHAM_Z_STREAM_ERROR;
  384. lzham_compress_state_ptr pComp = (lzham_compress_state_ptr)pStream->state;
  385. if (!pComp)
  386. return LZHAM_Z_STREAM_ERROR;
  387. pComp = lzham_lib_compress_reinit(pComp);
  388. if (!pComp)
  389. return LZHAM_Z_STREAM_ERROR;
  390. pStream->state = (struct lzham_z_internal_state *)pComp;
  391. return LZHAM_Z_OK;
  392. }
  393. int lzham_lib_z_deflate(lzham_z_streamp pStream, int flush)
  394. {
  395. if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > LZHAM_Z_FINISH) || (!pStream->next_out))
  396. return LZHAM_Z_STREAM_ERROR;
  397. if (!pStream->avail_out)
  398. return LZHAM_Z_BUF_ERROR;
  399. if (flush == LZHAM_Z_PARTIAL_FLUSH)
  400. flush = LZHAM_Z_SYNC_FLUSH;
  401. int lzham_status = LZHAM_Z_OK;
  402. lzham_z_ulong orig_total_in = pStream->total_in, orig_total_out = pStream->total_out;
  403. for ( ; ; )
  404. {
  405. size_t in_bytes = pStream->avail_in, out_bytes = pStream->avail_out;
  406. lzham_compress_state_ptr pComp = (lzham_compress_state_ptr)pStream->state;
  407. lzham_compress_state *pState = static_cast<lzham_compress_state*>(pComp);
  408. lzham_compress_status_t status = lzham_lib_compress2(
  409. pComp,
  410. pStream->next_in, &in_bytes,
  411. pStream->next_out, &out_bytes,
  412. (lzham_flush_t)flush);
  413. pStream->next_in += (uint)in_bytes;
  414. pStream->avail_in -= (uint)in_bytes;
  415. pStream->total_in += (uint)in_bytes;
  416. pStream->next_out += (uint)out_bytes;
  417. pStream->avail_out -= (uint)out_bytes;
  418. pStream->total_out += (uint)out_bytes;
  419. pStream->adler = pState->m_compressor.get_src_adler32();
  420. if (status >= LZHAM_COMP_STATUS_FIRST_FAILURE_CODE)
  421. {
  422. lzham_status = LZHAM_Z_STREAM_ERROR;
  423. break;
  424. }
  425. else if (status == LZHAM_COMP_STATUS_SUCCESS)
  426. {
  427. lzham_status = LZHAM_Z_STREAM_END;
  428. break;
  429. }
  430. else if (!pStream->avail_out)
  431. break;
  432. else if ((!pStream->avail_in) && (flush != LZHAM_Z_FINISH))
  433. {
  434. if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
  435. break;
  436. return LZHAM_Z_BUF_ERROR; // Can't make forward progress without some input.
  437. }
  438. }
  439. return lzham_status;
  440. }
  441. int lzham_lib_z_deflateEnd(lzham_z_streamp pStream)
  442. {
  443. if (!pStream)
  444. return LZHAM_Z_STREAM_ERROR;
  445. lzham_compress_state_ptr pComp = (lzham_compress_state_ptr)pStream->state;
  446. if (pComp)
  447. {
  448. pStream->adler = lzham_lib_compress_deinit(pComp);
  449. pStream->state = NULL;
  450. }
  451. return LZHAM_Z_OK;
  452. }
  453. lzham_z_ulong lzham_lib_z_deflateBound(lzham_z_streamp pStream, lzham_z_ulong source_len)
  454. {
  455. LZHAM_NOTE_UNUSED(pStream);
  456. return 64 + source_len + ((source_len + 4095) / 4096) * 4;
  457. }
  458. int lzham_lib_z_compress2(unsigned char *pDest, lzham_z_ulong *pDest_len, const unsigned char *pSource, lzham_z_ulong source_len, int level)
  459. {
  460. int status;
  461. lzham_z_stream stream;
  462. memset(&stream, 0, sizeof(stream));
  463. // In case lzham_z_ulong is 64-bits (argh I hate longs).
  464. if ((source_len | *pDest_len) > 0xFFFFFFFFU)
  465. return LZHAM_Z_PARAM_ERROR;
  466. stream.next_in = pSource;
  467. stream.avail_in = (uint)source_len;
  468. stream.next_out = pDest;
  469. stream.avail_out = (uint)*pDest_len;
  470. status = lzham_lib_z_deflateInit(&stream, level);
  471. if (status != LZHAM_Z_OK)
  472. return status;
  473. status = lzham_lib_z_deflate(&stream, LZHAM_Z_FINISH);
  474. if (status != LZHAM_Z_STREAM_END)
  475. {
  476. lzham_lib_z_deflateEnd(&stream);
  477. return (status == LZHAM_Z_OK) ? LZHAM_Z_BUF_ERROR : status;
  478. }
  479. *pDest_len = stream.total_out;
  480. return lzham_lib_z_deflateEnd(&stream);
  481. }
  482. int lzham_lib_z_compress(unsigned char *pDest, lzham_z_ulong *pDest_len, const unsigned char *pSource, lzham_z_ulong source_len)
  483. {
  484. return lzham_lib_z_compress2(pDest, pDest_len, pSource, source_len, (int)LZHAM_Z_DEFAULT_COMPRESSION);
  485. }
  486. lzham_z_ulong lzham_lib_z_compressBound(lzham_z_ulong source_len)
  487. {
  488. return lzham_lib_z_deflateBound(NULL, source_len);
  489. }
  490. } // namespace lzham