mirror of
https://github.com/Xevion/easy7zip.git
synced 2025-12-07 03:15:00 -06:00
- changed to real Lizard code v1.0 (I used LZ5 v2.0) - add Lizard file handling, so '.liz' files can be used in windows - changed CompressDialog (Lizard has 4 entries in the methods now) - added Lizard icon
373 lines
16 KiB
C
373 lines
16 KiB
C
/*
|
|
Lizard - Fast LZ compression algorithm
|
|
Copyright (C) 2011-2016, Yann Collet
|
|
Copyright (C) 2016-2017, Przemyslaw Skibinski <inikep@gmail.com>
|
|
|
|
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 :
|
|
- Lizard source repository : https://github.com/inikep/lizard
|
|
*/
|
|
|
|
|
|
/**************************************
|
|
* Includes
|
|
**************************************/
|
|
//#define LIZARD_STATS 1 // 0=simple stats, 1=more, 2=full
|
|
#ifdef LIZARD_STATS
|
|
#include "test/lizard_stats.h"
|
|
#endif
|
|
#include "lizard_compress.h"
|
|
#include "lizard_decompress.h"
|
|
#include "lizard_common.h"
|
|
#include <stdio.h> // printf
|
|
#include <stdint.h> // intptr_t
|
|
|
|
|
|
/*-************************************
|
|
* Local Structures and types
|
|
**************************************/
|
|
typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive;
|
|
typedef enum { full = 0, partial = 1 } earlyEnd_directive;
|
|
|
|
#include "lizard_decompress_lz4.h"
|
|
#ifndef USE_LZ4_ONLY
|
|
#ifdef LIZARD_USE_TEST
|
|
#include "test/lizard_common_test.h"
|
|
#include "test/lizard_decompress_test.h"
|
|
#else
|
|
#include "lizard_decompress_liz.h"
|
|
#endif
|
|
#endif
|
|
#include "../zstd/huf.h"
|
|
|
|
|
|
/*-*****************************
|
|
* Decompression functions
|
|
*******************************/
|
|
|
|
FORCE_INLINE size_t Lizard_readStream(int flag, const BYTE** ip, const BYTE* const iend, BYTE* op, BYTE* const oend, const BYTE** streamPtr, const BYTE** streamEnd, int streamFlag)
|
|
{
|
|
if (!flag) {
|
|
if (*ip > iend - 3) return 0;
|
|
*streamPtr = *ip + 3;
|
|
*streamEnd = *streamPtr + MEM_readLE24(*ip);
|
|
if (*streamEnd < *streamPtr) return 0;
|
|
*ip = *streamEnd;
|
|
#ifdef LIZARD_STATS
|
|
uncompr_stream[streamFlag] += *streamEnd-*streamPtr;
|
|
#else
|
|
(void)streamFlag;
|
|
#endif
|
|
return 1;
|
|
} else {
|
|
#ifndef LIZARD_NO_HUFFMAN
|
|
size_t res, streamLen, comprStreamLen;
|
|
|
|
if (*ip > iend - 6) return 0;
|
|
streamLen = MEM_readLE24(*ip);
|
|
comprStreamLen = MEM_readLE24(*ip + 3);
|
|
|
|
if ((op > oend - streamLen) || (*ip + comprStreamLen > iend - 6)) return 0;
|
|
res = HUF_decompress(op, streamLen, *ip + 6, comprStreamLen);
|
|
if (HUF_isError(res) || (res != streamLen)) return 0;
|
|
|
|
*ip += comprStreamLen + 6;
|
|
*streamPtr = op;
|
|
*streamEnd = *streamPtr + streamLen;
|
|
#ifdef LIZARD_STATS
|
|
compr_stream[streamFlag] += comprStreamLen + 6;
|
|
decompr_stream[streamFlag] += *streamEnd-*streamPtr;
|
|
#endif
|
|
return 1;
|
|
#else
|
|
fprintf(stderr, "compiled with LIZARD_NO_HUFFMAN\n");
|
|
(void)op; (void)oend;
|
|
return 0;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
|
|
FORCE_INLINE int Lizard_decompress_generic(
|
|
const char* source,
|
|
char* const dest,
|
|
int inputSize,
|
|
int outputSize, /* this value is the max size of Output Buffer. */
|
|
int partialDecoding, /* full, partial */
|
|
int targetOutputSize, /* only used if partialDecoding==partial */
|
|
int dict, /* noDict, withPrefix64k, usingExtDict */
|
|
const BYTE* const lowPrefix, /* == dest if dict == noDict */
|
|
const BYTE* const dictStart, /* only if dict==usingExtDict */
|
|
const size_t dictSize /* note : = 0 if noDict */
|
|
)
|
|
{
|
|
/* Local Variables */
|
|
const BYTE* ip = (const BYTE*) source, *istart = (const BYTE*) source;
|
|
const BYTE* const iend = ip + inputSize;
|
|
BYTE* op = (BYTE*) dest;
|
|
BYTE* const oend = op + outputSize;
|
|
BYTE* oexit = op + targetOutputSize;
|
|
Lizard_parameters params;
|
|
Lizard_dstream_t ctx;
|
|
BYTE* decompFlagsBase, *decompOff24Base, *decompOff16Base, *decompLiteralsBase = NULL;
|
|
int res, compressionLevel;
|
|
|
|
if (inputSize < 1) { LIZARD_LOG_DECOMPRESS("inputSize=%d outputSize=%d targetOutputSize=%d partialDecoding=%d\n", inputSize, outputSize, targetOutputSize, partialDecoding); return 0; }
|
|
|
|
compressionLevel = *ip++;
|
|
|
|
if (compressionLevel < LIZARD_MIN_CLEVEL || compressionLevel > LIZARD_MAX_CLEVEL) {
|
|
LIZARD_LOG_DECOMPRESS("ERROR Lizard_decompress_generic inputSize=%d compressionLevel=%d\n", inputSize, compressionLevel);
|
|
return -1;
|
|
}
|
|
|
|
LIZARD_LOG_DECOMPRESS("Lizard_decompress_generic ip=%p inputSize=%d targetOutputSize=%d dest=%p outputSize=%d cLevel=%d dict=%d dictSize=%d dictStart=%p partialDecoding=%d\n", ip, inputSize, targetOutputSize, dest, outputSize, compressionLevel, dict, (int)dictSize, dictStart, partialDecoding);
|
|
|
|
decompLiteralsBase = (BYTE*)malloc(4*LIZARD_HUF_BLOCK_SIZE);
|
|
if (!decompLiteralsBase) return -1;
|
|
decompFlagsBase = decompLiteralsBase + LIZARD_HUF_BLOCK_SIZE;
|
|
decompOff24Base = decompFlagsBase + LIZARD_HUF_BLOCK_SIZE;
|
|
decompOff16Base = decompOff24Base + LIZARD_HUF_BLOCK_SIZE;
|
|
|
|
#ifdef LIZARD_STATS
|
|
init_stats();
|
|
#endif
|
|
(void)istart;
|
|
|
|
while (ip < iend)
|
|
{
|
|
res = *ip++;
|
|
if (res == LIZARD_FLAG_UNCOMPRESSED) /* uncompressed */
|
|
{
|
|
uint32_t length;
|
|
if (ip > iend - 3) { LIZARD_LOG_DECOMPRESS("UNCOMPRESSED ip[%p] > iend[%p] - 3\n", ip, iend); goto _output_error; }
|
|
length = MEM_readLE24(ip);
|
|
ip += 3;
|
|
// printf("%d: total=%d block=%d UNCOMPRESSED op=%p oexit=%p oend=%p\n", (int)(op-(BYTE*)dest) ,(int)(ip-istart), length, op, oexit, oend);
|
|
if (ip + length > iend || op + length > oend) { LIZARD_LOG_DECOMPRESS("UNCOMPRESSED ip[%p]+length[%d] > iend[%p]\n", ip, length, iend); goto _output_error; }
|
|
memcpy(op, ip, length);
|
|
op += length;
|
|
ip += length;
|
|
if ((partialDecoding) && (op >= oexit)) break;
|
|
#ifdef LIZARD_STATS
|
|
uncompr_stream[LIZARD_STREAM_UNCOMPRESSED] += length;
|
|
#endif
|
|
continue;
|
|
}
|
|
|
|
if (res&LIZARD_FLAG_LEN) {
|
|
LIZARD_LOG_DECOMPRESS("res=%d\n", res); goto _output_error;
|
|
}
|
|
|
|
if (ip > iend - 5*3) goto _output_error;
|
|
ctx.lenPtr = (const BYTE*)ip + 3;
|
|
ctx.lenEnd = ctx.lenPtr + MEM_readLE24(ip);
|
|
if (ctx.lenEnd < ctx.lenPtr || (ctx.lenEnd > iend - 3)) goto _output_error;
|
|
#ifdef LIZARD_STATS
|
|
uncompr_stream[LIZARD_STREAM_LEN] += ctx.lenEnd-ctx.lenPtr + 3;
|
|
#endif
|
|
ip = ctx.lenEnd;
|
|
|
|
{ size_t streamLen;
|
|
#ifdef LIZARD_USE_LOGS
|
|
const BYTE* ipos;
|
|
size_t comprFlagsLen, comprLiteralsLen, total;
|
|
#endif
|
|
streamLen = Lizard_readStream(res&LIZARD_FLAG_OFFSET16, &ip, iend, decompOff16Base, decompOff16Base + LIZARD_HUF_BLOCK_SIZE, &ctx.offset16Ptr, &ctx.offset16End, LIZARD_STREAM_OFFSET16);
|
|
if (streamLen == 0) goto _output_error;
|
|
|
|
streamLen = Lizard_readStream(res&LIZARD_FLAG_OFFSET24, &ip, iend, decompOff24Base, decompOff24Base + LIZARD_HUF_BLOCK_SIZE, &ctx.offset24Ptr, &ctx.offset24End, LIZARD_STREAM_OFFSET24);
|
|
if (streamLen == 0) goto _output_error;
|
|
|
|
#ifdef LIZARD_USE_LOGS
|
|
ipos = ip;
|
|
streamLen = Lizard_readStream(res&LIZARD_FLAG_FLAGS, &ip, iend, decompFlagsBase, decompFlagsBase + LIZARD_HUF_BLOCK_SIZE, &ctx.flagsPtr, &ctx.flagsEnd, LIZARD_STREAM_FLAGS);
|
|
if (streamLen == 0) goto _output_error;
|
|
streamLen = (size_t)(ctx.flagsEnd-ctx.flagsPtr);
|
|
comprFlagsLen = ((size_t)(ip - ipos) + 3 >= streamLen) ? 0 : (size_t)(ip - ipos);
|
|
ipos = ip;
|
|
#else
|
|
streamLen = Lizard_readStream(res&LIZARD_FLAG_FLAGS, &ip, iend, decompFlagsBase, decompFlagsBase + LIZARD_HUF_BLOCK_SIZE, &ctx.flagsPtr, &ctx.flagsEnd, LIZARD_STREAM_FLAGS);
|
|
if (streamLen == 0) goto _output_error;
|
|
#endif
|
|
|
|
streamLen = Lizard_readStream(res&LIZARD_FLAG_LITERALS, &ip, iend, decompLiteralsBase, decompLiteralsBase + LIZARD_HUF_BLOCK_SIZE, &ctx.literalsPtr, &ctx.literalsEnd, LIZARD_STREAM_LITERALS);
|
|
if (streamLen == 0) goto _output_error;
|
|
#ifdef LIZARD_USE_LOGS
|
|
streamLen = (size_t)(ctx.literalsEnd-ctx.literalsPtr);
|
|
comprLiteralsLen = ((size_t)(ip - ipos) + 3 >= streamLen) ? 0 : (size_t)(ip - ipos);
|
|
total = (size_t)(ip-(ctx.lenEnd-1));
|
|
#endif
|
|
|
|
if (ip > iend) goto _output_error;
|
|
|
|
LIZARD_LOG_DECOMPRESS("%d: total=%d block=%d flagsLen=%d(HUF=%d) literalsLen=%d(HUF=%d) offset16Len=%d offset24Len=%d lengthsLen=%d \n", (int)(op-(BYTE*)dest) ,(int)(ip-istart), (int)total,
|
|
(int)(ctx.flagsEnd-ctx.flagsPtr), (int)comprFlagsLen, (int)(ctx.literalsEnd-ctx.literalsPtr), (int)comprLiteralsLen,
|
|
(int)(ctx.offset16End-ctx.offset16Ptr), (int)(ctx.offset24End-ctx.offset24Ptr), (int)(ctx.lenEnd-ctx.lenPtr));
|
|
}
|
|
|
|
ctx.last_off = -LIZARD_INIT_LAST_OFFSET;
|
|
params = Lizard_defaultParameters[compressionLevel - LIZARD_MIN_CLEVEL];
|
|
if (params.decompressType == Lizard_coderwords_LZ4)
|
|
res = Lizard_decompress_LZ4(&ctx, op, outputSize, partialDecoding, targetOutputSize, dict, lowPrefix, dictStart, dictSize, compressionLevel);
|
|
else
|
|
#ifdef USE_LZ4_ONLY
|
|
res = Lizard_decompress_LZ4(&ctx, op, outputSize, partialDecoding, targetOutputSize, dict, lowPrefix, dictStart, dictSize, compressionLevel);
|
|
#else
|
|
res = Lizard_decompress_LIZv1(&ctx, op, outputSize, partialDecoding, targetOutputSize, dict, lowPrefix, dictStart, dictSize, compressionLevel);
|
|
#endif
|
|
LIZARD_LOG_DECOMPRESS("Lizard_decompress_generic res=%d inputSize=%d\n", res, (int)(ctx.literalsEnd-ctx.lenEnd));
|
|
|
|
if (res <= 0) { free(decompLiteralsBase); return res; }
|
|
|
|
op += res;
|
|
outputSize -= res;
|
|
if ((partialDecoding) && (op >= oexit)) break;
|
|
}
|
|
|
|
#ifdef LIZARD_STATS
|
|
print_stats();
|
|
#endif
|
|
|
|
LIZARD_LOG_DECOMPRESS("Lizard_decompress_generic total=%d\n", (int)(op-(BYTE*)dest));
|
|
free(decompLiteralsBase);
|
|
return (int)(op-(BYTE*)dest);
|
|
|
|
_output_error:
|
|
LIZARD_LOG_DECOMPRESS("Lizard_decompress_generic ERROR ip=%p iend=%p\n", ip, iend);
|
|
free(decompLiteralsBase);
|
|
return -1;
|
|
}
|
|
|
|
|
|
int Lizard_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize)
|
|
{
|
|
return Lizard_decompress_generic(source, dest, compressedSize, maxDecompressedSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
|
|
}
|
|
|
|
int Lizard_decompress_safe_partial(const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize)
|
|
{
|
|
return Lizard_decompress_generic(source, dest, compressedSize, maxDecompressedSize, partial, targetOutputSize, noDict, (BYTE*)dest, NULL, 0);
|
|
}
|
|
|
|
|
|
/*===== streaming decompression functions =====*/
|
|
|
|
|
|
/*
|
|
* If you prefer dynamic allocation methods,
|
|
* Lizard_createStreamDecode()
|
|
* provides a pointer (void*) towards an initialized Lizard_streamDecode_t structure.
|
|
*/
|
|
Lizard_streamDecode_t* Lizard_createStreamDecode(void)
|
|
{
|
|
Lizard_streamDecode_t* lizards = (Lizard_streamDecode_t*) ALLOCATOR(1, sizeof(Lizard_streamDecode_t));
|
|
return lizards;
|
|
}
|
|
|
|
int Lizard_freeStreamDecode (Lizard_streamDecode_t* Lizard_stream)
|
|
{
|
|
FREEMEM(Lizard_stream);
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* Lizard_setStreamDecode() :
|
|
* Use this function to instruct where to find the dictionary.
|
|
* This function is not necessary if previous data is still available where it was decoded.
|
|
* Loading a size of 0 is allowed (same effect as no dictionary).
|
|
* Return : 1 if OK, 0 if error
|
|
*/
|
|
int Lizard_setStreamDecode (Lizard_streamDecode_t* Lizard_streamDecode, const char* dictionary, int dictSize)
|
|
{
|
|
Lizard_streamDecode_t* lizardsd = (Lizard_streamDecode_t*) Lizard_streamDecode;
|
|
lizardsd->prefixSize = (size_t) dictSize;
|
|
lizardsd->prefixEnd = (const BYTE*) dictionary + dictSize;
|
|
lizardsd->externalDict = NULL;
|
|
lizardsd->extDictSize = 0;
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
*_continue() :
|
|
These decoding functions allow decompression of multiple blocks in "streaming" mode.
|
|
Previously decoded blocks must still be available at the memory position where they were decoded.
|
|
If it's not possible, save the relevant part of decoded data into a safe buffer,
|
|
and indicate where it stands using Lizard_setStreamDecode()
|
|
*/
|
|
int Lizard_decompress_safe_continue (Lizard_streamDecode_t* Lizard_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize)
|
|
{
|
|
Lizard_streamDecode_t* lizardsd = (Lizard_streamDecode_t*) Lizard_streamDecode;
|
|
int result;
|
|
|
|
if (lizardsd->prefixEnd == (BYTE*)dest) {
|
|
result = Lizard_decompress_generic(source, dest, compressedSize, maxOutputSize,
|
|
full, 0, usingExtDict, lizardsd->prefixEnd - lizardsd->prefixSize, lizardsd->externalDict, lizardsd->extDictSize);
|
|
if (result <= 0) return result;
|
|
lizardsd->prefixSize += result;
|
|
lizardsd->prefixEnd += result;
|
|
} else {
|
|
lizardsd->extDictSize = lizardsd->prefixSize;
|
|
lizardsd->externalDict = lizardsd->prefixEnd - lizardsd->extDictSize;
|
|
result = Lizard_decompress_generic(source, dest, compressedSize, maxOutputSize,
|
|
full, 0, usingExtDict, (BYTE*)dest, lizardsd->externalDict, lizardsd->extDictSize);
|
|
if (result <= 0) return result;
|
|
lizardsd->prefixSize = result;
|
|
lizardsd->prefixEnd = (BYTE*)dest + result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
/*
|
|
Advanced decoding functions :
|
|
*_usingDict() :
|
|
These decoding functions work the same as "_continue" ones,
|
|
the dictionary must be explicitly provided within parameters
|
|
*/
|
|
|
|
int Lizard_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
|
|
{
|
|
if (dictSize==0)
|
|
return Lizard_decompress_generic(source, dest, compressedSize, maxOutputSize, full, 0, noDict, (BYTE*)dest, NULL, 0);
|
|
if (dictStart+dictSize == dest)
|
|
{
|
|
if (dictSize >= (int)(LIZARD_DICT_SIZE - 1))
|
|
return Lizard_decompress_generic(source, dest, compressedSize, maxOutputSize, full, 0, withPrefix64k, (BYTE*)dest-LIZARD_DICT_SIZE, NULL, 0);
|
|
return Lizard_decompress_generic(source, dest, compressedSize, maxOutputSize, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0);
|
|
}
|
|
return Lizard_decompress_generic(source, dest, compressedSize, maxOutputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
|
|
}
|
|
|
|
/* debug function */
|
|
int Lizard_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize)
|
|
{
|
|
return Lizard_decompress_generic(source, dest, compressedSize, maxOutputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize);
|
|
}
|
|
|