lz4file.c 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. * LZ4 file library
  3. * Copyright (C) 2022, Xiaomi Inc.
  4. *
  5. * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php)
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are
  9. * met:
  10. *
  11. * - Redistributions of source code must retain the above copyright
  12. * notice, this list of conditions and the following disclaimer.
  13. * - Redistributions in binary form must reproduce the above
  14. * copyright notice, this list of conditions and the following disclaimer
  15. * in the documentation and/or other materials provided with the
  16. * distribution.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. * You can contact the author at :
  31. * - LZ4 homepage : http://www.lz4.org
  32. * - LZ4 source repository : https://github.com/lz4/lz4
  33. */
  34. #include <stdlib.h>
  35. #include <string.h>
  36. #include "lz4.h"
  37. #include "lz4file.h"
  38. struct LZ4_readFile_s {
  39. LZ4F_dctx* dctxPtr;
  40. FILE* fp;
  41. LZ4_byte* srcBuf;
  42. size_t srcBufNext;
  43. size_t srcBufSize;
  44. size_t srcBufMaxSize;
  45. };
  46. struct LZ4_writeFile_s {
  47. LZ4F_cctx* cctxPtr;
  48. FILE* fp;
  49. LZ4_byte* dstBuf;
  50. size_t maxWriteSize;
  51. size_t dstBufMaxSize;
  52. LZ4F_errorCode_t errCode;
  53. };
  54. LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp)
  55. {
  56. char buf[LZ4F_HEADER_SIZE_MAX];
  57. size_t consumedSize;
  58. LZ4F_errorCode_t ret;
  59. LZ4F_frameInfo_t info;
  60. if (fp == NULL || lz4fRead == NULL) {
  61. return -LZ4F_ERROR_GENERIC;
  62. }
  63. *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t));
  64. if (*lz4fRead == NULL) {
  65. return -LZ4F_ERROR_allocation_failed;
  66. }
  67. ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_getVersion());
  68. if (LZ4F_isError(ret)) {
  69. free(*lz4fRead);
  70. return ret;
  71. }
  72. (*lz4fRead)->fp = fp;
  73. consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp);
  74. if (consumedSize != sizeof(buf)) {
  75. free(*lz4fRead);
  76. return -LZ4F_ERROR_GENERIC;
  77. }
  78. ret = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize);
  79. if (LZ4F_isError(ret)) {
  80. LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
  81. free(*lz4fRead);
  82. return ret;
  83. }
  84. switch (info.blockSizeID) {
  85. case LZ4F_default :
  86. case LZ4F_max64KB :
  87. (*lz4fRead)->srcBufMaxSize = 64 * 1024;
  88. break;
  89. case LZ4F_max256KB:
  90. (*lz4fRead)->srcBufMaxSize = 256 * 1024;
  91. break;
  92. case LZ4F_max1MB:
  93. (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024;
  94. break;
  95. case LZ4F_max4MB:
  96. (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024;
  97. break;
  98. default:
  99. LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
  100. free(*lz4fRead);
  101. return -LZ4F_ERROR_maxBlockSize_invalid;
  102. }
  103. (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize);
  104. if ((*lz4fRead)->srcBuf == NULL) {
  105. LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr);
  106. free(lz4fRead);
  107. return -LZ4F_ERROR_allocation_failed;
  108. }
  109. (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize;
  110. memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize);
  111. return ret;
  112. }
  113. size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size)
  114. {
  115. LZ4_byte* p = (LZ4_byte*)buf;
  116. size_t next = 0;
  117. if (lz4fRead == NULL || buf == NULL)
  118. return -LZ4F_ERROR_GENERIC;
  119. while (next < size) {
  120. size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext;
  121. size_t dstsize = size - next;
  122. size_t ret;
  123. if (srcsize == 0) {
  124. ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp);
  125. if (ret > 0) {
  126. lz4fRead->srcBufSize = ret;
  127. srcsize = lz4fRead->srcBufSize;
  128. lz4fRead->srcBufNext = 0;
  129. }
  130. else if (ret == 0) {
  131. break;
  132. }
  133. else {
  134. return -LZ4F_ERROR_GENERIC;
  135. }
  136. }
  137. ret = LZ4F_decompress(lz4fRead->dctxPtr,
  138. p, &dstsize,
  139. lz4fRead->srcBuf + lz4fRead->srcBufNext,
  140. &srcsize,
  141. NULL);
  142. if (LZ4F_isError(ret)) {
  143. return ret;
  144. }
  145. lz4fRead->srcBufNext += srcsize;
  146. next += dstsize;
  147. p += dstsize;
  148. }
  149. return next;
  150. }
  151. LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead)
  152. {
  153. if (lz4fRead == NULL)
  154. return -LZ4F_ERROR_GENERIC;
  155. LZ4F_freeDecompressionContext(lz4fRead->dctxPtr);
  156. free(lz4fRead->srcBuf);
  157. free(lz4fRead);
  158. return LZ4F_OK_NoError;
  159. }
  160. LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr)
  161. {
  162. LZ4_byte buf[LZ4F_HEADER_SIZE_MAX];
  163. size_t ret;
  164. if (fp == NULL || lz4fWrite == NULL)
  165. return -LZ4F_ERROR_GENERIC;
  166. *lz4fWrite = (LZ4_writeFile_t*)malloc(sizeof(LZ4_writeFile_t));
  167. if (*lz4fWrite == NULL) {
  168. return -LZ4F_ERROR_allocation_failed;
  169. }
  170. if (prefsPtr != NULL) {
  171. switch (prefsPtr->frameInfo.blockSizeID) {
  172. case LZ4F_default :
  173. case LZ4F_max64KB :
  174. (*lz4fWrite)->maxWriteSize = 64 * 1024;
  175. break;
  176. case LZ4F_max256KB:
  177. (*lz4fWrite)->maxWriteSize = 256 * 1024;
  178. break;
  179. case LZ4F_max1MB:
  180. (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024;
  181. break;
  182. case LZ4F_max4MB:
  183. (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024;
  184. break;
  185. default:
  186. free(lz4fWrite);
  187. return -LZ4F_ERROR_maxBlockSize_invalid;
  188. }
  189. } else {
  190. (*lz4fWrite)->maxWriteSize = 64 * 1024;
  191. }
  192. (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr);
  193. (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize);
  194. if ((*lz4fWrite)->dstBuf == NULL) {
  195. free(*lz4fWrite);
  196. return -LZ4F_ERROR_allocation_failed;
  197. }
  198. ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_getVersion());
  199. if (LZ4F_isError(ret)) {
  200. free((*lz4fWrite)->dstBuf);
  201. free(*lz4fWrite);
  202. return ret;
  203. }
  204. ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr);
  205. if (LZ4F_isError(ret)) {
  206. LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);
  207. free((*lz4fWrite)->dstBuf);
  208. free(*lz4fWrite);
  209. return ret;
  210. }
  211. if (ret != fwrite(buf, 1, ret, fp)) {
  212. LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr);
  213. free((*lz4fWrite)->dstBuf);
  214. free(*lz4fWrite);
  215. return -LZ4F_ERROR_GENERIC;
  216. }
  217. (*lz4fWrite)->fp = fp;
  218. (*lz4fWrite)->errCode = LZ4F_OK_NoError;
  219. return LZ4F_OK_NoError;
  220. }
  221. size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size)
  222. {
  223. LZ4_byte* p = (LZ4_byte*)buf;
  224. size_t remain = size;
  225. size_t chunk;
  226. size_t ret;
  227. if (lz4fWrite == NULL || buf == NULL)
  228. return -LZ4F_ERROR_GENERIC;
  229. while (remain) {
  230. if (remain > lz4fWrite->maxWriteSize)
  231. chunk = lz4fWrite->maxWriteSize;
  232. else
  233. chunk = remain;
  234. ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr,
  235. lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
  236. p, chunk,
  237. NULL);
  238. if (LZ4F_isError(ret)) {
  239. lz4fWrite->errCode = ret;
  240. return ret;
  241. }
  242. if(ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
  243. lz4fWrite->errCode = -LZ4F_ERROR_GENERIC;
  244. return -LZ4F_ERROR_GENERIC;
  245. }
  246. p += chunk;
  247. remain -= chunk;
  248. }
  249. return size;
  250. }
  251. LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite)
  252. {
  253. LZ4F_errorCode_t ret = LZ4F_OK_NoError;
  254. if (lz4fWrite == NULL)
  255. return -LZ4F_ERROR_GENERIC;
  256. if (lz4fWrite->errCode == LZ4F_OK_NoError) {
  257. ret = LZ4F_compressEnd(lz4fWrite->cctxPtr,
  258. lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
  259. NULL);
  260. if (LZ4F_isError(ret)) {
  261. goto out;
  262. }
  263. if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
  264. ret = -LZ4F_ERROR_GENERIC;
  265. }
  266. }
  267. out:
  268. LZ4F_freeCompressionContext(lz4fWrite->cctxPtr);
  269. free(lz4fWrite->dstBuf);
  270. free(lz4fWrite);
  271. return ret;
  272. }