lz4file.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  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> /* malloc, free */
  35. #include <string.h>
  36. #include <assert.h>
  37. #include "lz4.h"
  38. #include "lz4file.h"
  39. static LZ4F_errorCode_t returnErrorCode(LZ4F_errorCodes code)
  40. {
  41. return (LZ4F_errorCode_t)-(ptrdiff_t)code;
  42. }
  43. #undef RETURN_ERROR
  44. #define RETURN_ERROR(e) return returnErrorCode(LZ4F_ERROR_ ## e)
  45. /* ===== read API ===== */
  46. struct LZ4_readFile_s {
  47. LZ4F_dctx* dctxPtr;
  48. FILE* fp;
  49. LZ4_byte* srcBuf;
  50. size_t srcBufNext;
  51. size_t srcBufSize;
  52. size_t srcBufMaxSize;
  53. };
  54. static void LZ4F_freeReadFile(LZ4_readFile_t* lz4fRead)
  55. {
  56. if (lz4fRead==NULL) return;
  57. LZ4F_freeDecompressionContext(lz4fRead->dctxPtr);
  58. free(lz4fRead->srcBuf);
  59. free(lz4fRead);
  60. }
  61. static void LZ4F_freeAndNullReadFile(LZ4_readFile_t** statePtr)
  62. {
  63. assert(statePtr != NULL);
  64. LZ4F_freeReadFile(*statePtr);
  65. *statePtr = NULL;
  66. }
  67. LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp)
  68. {
  69. char buf[LZ4F_HEADER_SIZE_MAX];
  70. size_t consumedSize;
  71. LZ4F_errorCode_t ret;
  72. if (fp == NULL || lz4fRead == NULL) {
  73. RETURN_ERROR(parameter_null);
  74. }
  75. *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t));
  76. if (*lz4fRead == NULL) {
  77. RETURN_ERROR(allocation_failed);
  78. }
  79. ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_VERSION);
  80. if (LZ4F_isError(ret)) {
  81. LZ4F_freeAndNullReadFile(lz4fRead);
  82. return ret;
  83. }
  84. (*lz4fRead)->fp = fp;
  85. consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp);
  86. if (consumedSize != sizeof(buf)) {
  87. LZ4F_freeAndNullReadFile(lz4fRead);
  88. RETURN_ERROR(io_read);
  89. }
  90. { LZ4F_frameInfo_t info;
  91. LZ4F_errorCode_t const r = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize);
  92. if (LZ4F_isError(r)) {
  93. LZ4F_freeAndNullReadFile(lz4fRead);
  94. return r;
  95. }
  96. switch (info.blockSizeID) {
  97. case LZ4F_default :
  98. case LZ4F_max64KB :
  99. (*lz4fRead)->srcBufMaxSize = 64 * 1024;
  100. break;
  101. case LZ4F_max256KB:
  102. (*lz4fRead)->srcBufMaxSize = 256 * 1024;
  103. break;
  104. case LZ4F_max1MB:
  105. (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024;
  106. break;
  107. case LZ4F_max4MB:
  108. (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024;
  109. break;
  110. default:
  111. LZ4F_freeAndNullReadFile(lz4fRead);
  112. RETURN_ERROR(maxBlockSize_invalid);
  113. }
  114. }
  115. (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize);
  116. if ((*lz4fRead)->srcBuf == NULL) {
  117. LZ4F_freeAndNullReadFile(lz4fRead);
  118. RETURN_ERROR(allocation_failed);
  119. }
  120. (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize;
  121. memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize);
  122. return ret;
  123. }
  124. size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size)
  125. {
  126. LZ4_byte* p = (LZ4_byte*)buf;
  127. size_t next = 0;
  128. if (lz4fRead == NULL || buf == NULL)
  129. RETURN_ERROR(parameter_null);
  130. while (next < size) {
  131. size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext;
  132. size_t dstsize = size - next;
  133. size_t ret;
  134. if (srcsize == 0) {
  135. ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp);
  136. if (ret > 0) {
  137. lz4fRead->srcBufSize = ret;
  138. srcsize = lz4fRead->srcBufSize;
  139. lz4fRead->srcBufNext = 0;
  140. } else if (ret == 0) {
  141. break;
  142. } else {
  143. RETURN_ERROR(io_read);
  144. }
  145. }
  146. ret = LZ4F_decompress(lz4fRead->dctxPtr,
  147. p, &dstsize,
  148. lz4fRead->srcBuf + lz4fRead->srcBufNext,
  149. &srcsize,
  150. NULL);
  151. if (LZ4F_isError(ret)) {
  152. return ret;
  153. }
  154. lz4fRead->srcBufNext += srcsize;
  155. next += dstsize;
  156. p += dstsize;
  157. }
  158. return next;
  159. }
  160. LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead)
  161. {
  162. if (lz4fRead == NULL)
  163. RETURN_ERROR(parameter_null);
  164. LZ4F_freeReadFile(lz4fRead);
  165. return LZ4F_OK_NoError;
  166. }
  167. /* ===== write API ===== */
  168. struct LZ4_writeFile_s {
  169. LZ4F_cctx* cctxPtr;
  170. FILE* fp;
  171. LZ4_byte* dstBuf;
  172. size_t maxWriteSize;
  173. size_t dstBufMaxSize;
  174. LZ4F_errorCode_t errCode;
  175. };
  176. static void LZ4F_freeWriteFile(LZ4_writeFile_t* state)
  177. {
  178. if (state == NULL) return;
  179. LZ4F_freeCompressionContext(state->cctxPtr);
  180. free(state->dstBuf);
  181. free(state);
  182. }
  183. static void LZ4F_freeAndNullWriteFile(LZ4_writeFile_t** statePtr)
  184. {
  185. assert(statePtr != NULL);
  186. LZ4F_freeWriteFile(*statePtr);
  187. *statePtr = NULL;
  188. }
  189. LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr)
  190. {
  191. LZ4_byte buf[LZ4F_HEADER_SIZE_MAX];
  192. size_t ret;
  193. if (fp == NULL || lz4fWrite == NULL)
  194. RETURN_ERROR(parameter_null);
  195. *lz4fWrite = (LZ4_writeFile_t*)calloc(1, sizeof(LZ4_writeFile_t));
  196. if (*lz4fWrite == NULL) {
  197. RETURN_ERROR(allocation_failed);
  198. }
  199. if (prefsPtr != NULL) {
  200. switch (prefsPtr->frameInfo.blockSizeID) {
  201. case LZ4F_default :
  202. case LZ4F_max64KB :
  203. (*lz4fWrite)->maxWriteSize = 64 * 1024;
  204. break;
  205. case LZ4F_max256KB:
  206. (*lz4fWrite)->maxWriteSize = 256 * 1024;
  207. break;
  208. case LZ4F_max1MB:
  209. (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024;
  210. break;
  211. case LZ4F_max4MB:
  212. (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024;
  213. break;
  214. default:
  215. LZ4F_freeAndNullWriteFile(lz4fWrite);
  216. RETURN_ERROR(maxBlockSize_invalid);
  217. }
  218. } else {
  219. (*lz4fWrite)->maxWriteSize = 64 * 1024;
  220. }
  221. (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr);
  222. (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize);
  223. if ((*lz4fWrite)->dstBuf == NULL) {
  224. LZ4F_freeAndNullWriteFile(lz4fWrite);
  225. RETURN_ERROR(allocation_failed);
  226. }
  227. ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_VERSION);
  228. if (LZ4F_isError(ret)) {
  229. LZ4F_freeAndNullWriteFile(lz4fWrite);
  230. return ret;
  231. }
  232. ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr);
  233. if (LZ4F_isError(ret)) {
  234. LZ4F_freeAndNullWriteFile(lz4fWrite);
  235. return ret;
  236. }
  237. if (ret != fwrite(buf, 1, ret, fp)) {
  238. LZ4F_freeAndNullWriteFile(lz4fWrite);
  239. RETURN_ERROR(io_write);
  240. }
  241. (*lz4fWrite)->fp = fp;
  242. (*lz4fWrite)->errCode = LZ4F_OK_NoError;
  243. return LZ4F_OK_NoError;
  244. }
  245. size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, const void* buf, size_t size)
  246. {
  247. const LZ4_byte* p = (const LZ4_byte*)buf;
  248. size_t remain = size;
  249. size_t chunk;
  250. size_t ret;
  251. if (lz4fWrite == NULL || buf == NULL)
  252. RETURN_ERROR(parameter_null);
  253. while (remain) {
  254. if (remain > lz4fWrite->maxWriteSize)
  255. chunk = lz4fWrite->maxWriteSize;
  256. else
  257. chunk = remain;
  258. ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr,
  259. lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
  260. p, chunk,
  261. NULL);
  262. if (LZ4F_isError(ret)) {
  263. lz4fWrite->errCode = ret;
  264. return ret;
  265. }
  266. if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
  267. lz4fWrite->errCode = returnErrorCode(LZ4F_ERROR_io_write);
  268. RETURN_ERROR(io_write);
  269. }
  270. p += chunk;
  271. remain -= chunk;
  272. }
  273. return size;
  274. }
  275. LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite)
  276. {
  277. LZ4F_errorCode_t ret = LZ4F_OK_NoError;
  278. if (lz4fWrite == NULL) {
  279. RETURN_ERROR(parameter_null);
  280. }
  281. if (lz4fWrite->errCode == LZ4F_OK_NoError) {
  282. ret = LZ4F_compressEnd(lz4fWrite->cctxPtr,
  283. lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize,
  284. NULL);
  285. if (LZ4F_isError(ret)) {
  286. goto out;
  287. }
  288. if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) {
  289. ret = returnErrorCode(LZ4F_ERROR_io_write);
  290. }
  291. }
  292. out:
  293. LZ4F_freeWriteFile(lz4fWrite);
  294. return ret;
  295. }