diff options
Diffstat (limited to 'lib/lz4file.c')
-rw-r--r-- | lib/lz4file.c | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/lib/lz4file.c b/lib/lz4file.c new file mode 100644 index 0000000..eaf9b17 --- /dev/null +++ b/lib/lz4file.c @@ -0,0 +1,311 @@ +/* + * LZ4 file library + * Copyright (C) 2022, Xiaomi Inc. + * + * BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * You can contact the author at : + * - LZ4 homepage : http://www.lz4.org + * - LZ4 source repository : https://github.com/lz4/lz4 + */ +#include <stdlib.h> +#include <string.h> +#include "lz4.h" +#include "lz4file.h" + +struct LZ4_readFile_s { + LZ4F_dctx* dctxPtr; + FILE* fp; + LZ4_byte* srcBuf; + size_t srcBufNext; + size_t srcBufSize; + size_t srcBufMaxSize; +}; + +struct LZ4_writeFile_s { + LZ4F_cctx* cctxPtr; + FILE* fp; + LZ4_byte* dstBuf; + size_t maxWriteSize; + size_t dstBufMaxSize; + LZ4F_errorCode_t errCode; +}; + +LZ4F_errorCode_t LZ4F_readOpen(LZ4_readFile_t** lz4fRead, FILE* fp) +{ + char buf[LZ4F_HEADER_SIZE_MAX]; + size_t consumedSize; + LZ4F_errorCode_t ret; + LZ4F_frameInfo_t info; + + if (fp == NULL || lz4fRead == NULL) { + return -LZ4F_ERROR_GENERIC; + } + + *lz4fRead = (LZ4_readFile_t*)calloc(1, sizeof(LZ4_readFile_t)); + if (*lz4fRead == NULL) { + return -LZ4F_ERROR_allocation_failed; + } + + ret = LZ4F_createDecompressionContext(&(*lz4fRead)->dctxPtr, LZ4F_getVersion()); + if (LZ4F_isError(ret)) { + free(*lz4fRead); + return ret; + } + + (*lz4fRead)->fp = fp; + consumedSize = fread(buf, 1, sizeof(buf), (*lz4fRead)->fp); + if (consumedSize != sizeof(buf)) { + free(*lz4fRead); + return -LZ4F_ERROR_GENERIC; + } + + ret = LZ4F_getFrameInfo((*lz4fRead)->dctxPtr, &info, buf, &consumedSize); + if (LZ4F_isError(ret)) { + LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); + free(*lz4fRead); + return ret; + } + + switch (info.blockSizeID) { + case LZ4F_default : + case LZ4F_max64KB : + (*lz4fRead)->srcBufMaxSize = 64 * 1024; + break; + case LZ4F_max256KB: + (*lz4fRead)->srcBufMaxSize = 256 * 1024; + break; + case LZ4F_max1MB: + (*lz4fRead)->srcBufMaxSize = 1 * 1024 * 1024; + break; + case LZ4F_max4MB: + (*lz4fRead)->srcBufMaxSize = 4 * 1024 * 1024; + break; + default: + LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); + free(*lz4fRead); + return -LZ4F_ERROR_maxBlockSize_invalid; + } + + (*lz4fRead)->srcBuf = (LZ4_byte*)malloc((*lz4fRead)->srcBufMaxSize); + if ((*lz4fRead)->srcBuf == NULL) { + LZ4F_freeDecompressionContext((*lz4fRead)->dctxPtr); + free(lz4fRead); + return -LZ4F_ERROR_allocation_failed; + } + + (*lz4fRead)->srcBufSize = sizeof(buf) - consumedSize; + memcpy((*lz4fRead)->srcBuf, buf + consumedSize, (*lz4fRead)->srcBufSize); + + return ret; +} + +size_t LZ4F_read(LZ4_readFile_t* lz4fRead, void* buf, size_t size) +{ + LZ4_byte* p = (LZ4_byte*)buf; + size_t next = 0; + + if (lz4fRead == NULL || buf == NULL) + return -LZ4F_ERROR_GENERIC; + + while (next < size) { + size_t srcsize = lz4fRead->srcBufSize - lz4fRead->srcBufNext; + size_t dstsize = size - next; + size_t ret; + + if (srcsize == 0) { + ret = fread(lz4fRead->srcBuf, 1, lz4fRead->srcBufMaxSize, lz4fRead->fp); + if (ret > 0) { + lz4fRead->srcBufSize = ret; + srcsize = lz4fRead->srcBufSize; + lz4fRead->srcBufNext = 0; + } + else if (ret == 0) { + break; + } + else { + return -LZ4F_ERROR_GENERIC; + } + } + + ret = LZ4F_decompress(lz4fRead->dctxPtr, + p, &dstsize, + lz4fRead->srcBuf + lz4fRead->srcBufNext, + &srcsize, + NULL); + if (LZ4F_isError(ret)) { + return ret; + } + + lz4fRead->srcBufNext += srcsize; + next += dstsize; + p += dstsize; + } + + return next; +} + +LZ4F_errorCode_t LZ4F_readClose(LZ4_readFile_t* lz4fRead) +{ + if (lz4fRead == NULL) + return -LZ4F_ERROR_GENERIC; + LZ4F_freeDecompressionContext(lz4fRead->dctxPtr); + free(lz4fRead->srcBuf); + free(lz4fRead); + return LZ4F_OK_NoError; +} + +LZ4F_errorCode_t LZ4F_writeOpen(LZ4_writeFile_t** lz4fWrite, FILE* fp, const LZ4F_preferences_t* prefsPtr) +{ + LZ4_byte buf[LZ4F_HEADER_SIZE_MAX]; + size_t ret; + + if (fp == NULL || lz4fWrite == NULL) + return -LZ4F_ERROR_GENERIC; + + *lz4fWrite = (LZ4_writeFile_t*)malloc(sizeof(LZ4_writeFile_t)); + if (*lz4fWrite == NULL) { + return -LZ4F_ERROR_allocation_failed; + } + if (prefsPtr != NULL) { + switch (prefsPtr->frameInfo.blockSizeID) { + case LZ4F_default : + case LZ4F_max64KB : + (*lz4fWrite)->maxWriteSize = 64 * 1024; + break; + case LZ4F_max256KB: + (*lz4fWrite)->maxWriteSize = 256 * 1024; + break; + case LZ4F_max1MB: + (*lz4fWrite)->maxWriteSize = 1 * 1024 * 1024; + break; + case LZ4F_max4MB: + (*lz4fWrite)->maxWriteSize = 4 * 1024 * 1024; + break; + default: + free(lz4fWrite); + return -LZ4F_ERROR_maxBlockSize_invalid; + } + } else { + (*lz4fWrite)->maxWriteSize = 64 * 1024; + } + + (*lz4fWrite)->dstBufMaxSize = LZ4F_compressBound((*lz4fWrite)->maxWriteSize, prefsPtr); + (*lz4fWrite)->dstBuf = (LZ4_byte*)malloc((*lz4fWrite)->dstBufMaxSize); + if ((*lz4fWrite)->dstBuf == NULL) { + free(*lz4fWrite); + return -LZ4F_ERROR_allocation_failed; + } + + ret = LZ4F_createCompressionContext(&(*lz4fWrite)->cctxPtr, LZ4F_getVersion()); + if (LZ4F_isError(ret)) { + free((*lz4fWrite)->dstBuf); + free(*lz4fWrite); + return ret; + } + + ret = LZ4F_compressBegin((*lz4fWrite)->cctxPtr, buf, LZ4F_HEADER_SIZE_MAX, prefsPtr); + if (LZ4F_isError(ret)) { + LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr); + free((*lz4fWrite)->dstBuf); + free(*lz4fWrite); + return ret; + } + + if (ret != fwrite(buf, 1, ret, fp)) { + LZ4F_freeCompressionContext((*lz4fWrite)->cctxPtr); + free((*lz4fWrite)->dstBuf); + free(*lz4fWrite); + return -LZ4F_ERROR_GENERIC; + } + + (*lz4fWrite)->fp = fp; + (*lz4fWrite)->errCode = LZ4F_OK_NoError; + return LZ4F_OK_NoError; +} + +size_t LZ4F_write(LZ4_writeFile_t* lz4fWrite, void* buf, size_t size) +{ + LZ4_byte* p = (LZ4_byte*)buf; + size_t remain = size; + size_t chunk; + size_t ret; + + if (lz4fWrite == NULL || buf == NULL) + return -LZ4F_ERROR_GENERIC; + while (remain) { + if (remain > lz4fWrite->maxWriteSize) + chunk = lz4fWrite->maxWriteSize; + else + chunk = remain; + + ret = LZ4F_compressUpdate(lz4fWrite->cctxPtr, + lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize, + p, chunk, + NULL); + if (LZ4F_isError(ret)) { + lz4fWrite->errCode = ret; + return ret; + } + + if(ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) { + lz4fWrite->errCode = -LZ4F_ERROR_GENERIC; + return -LZ4F_ERROR_GENERIC; + } + + p += chunk; + remain -= chunk; + } + + return size; +} + +LZ4F_errorCode_t LZ4F_writeClose(LZ4_writeFile_t* lz4fWrite) +{ + LZ4F_errorCode_t ret = LZ4F_OK_NoError; + + if (lz4fWrite == NULL) + return -LZ4F_ERROR_GENERIC; + + if (lz4fWrite->errCode == LZ4F_OK_NoError) { + ret = LZ4F_compressEnd(lz4fWrite->cctxPtr, + lz4fWrite->dstBuf, lz4fWrite->dstBufMaxSize, + NULL); + if (LZ4F_isError(ret)) { + goto out; + } + + if (ret != fwrite(lz4fWrite->dstBuf, 1, ret, lz4fWrite->fp)) { + ret = -LZ4F_ERROR_GENERIC; + } + } + +out: + LZ4F_freeCompressionContext(lz4fWrite->cctxPtr); + free(lz4fWrite->dstBuf); + free(lz4fWrite); + return ret; +} |