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