lz4file.c (9359B)
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 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 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 66 static void LZ4F_freeAndNullReadFile(LZ4_readFile_t** statePtr) 67 { 68 assert(statePtr != NULL); 69 LZ4F_freeReadFile(*statePtr); 70 *statePtr = NULL; 71 } 72 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 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 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 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 210 static void LZ4F_freeAndNullWriteFile(LZ4_writeFile_t** statePtr) 211 { 212 assert(statePtr != NULL); 213 LZ4F_freeWriteFile(*statePtr); 214 *statePtr = NULL; 215 } 216 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 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 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 }