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