• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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