mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 14:16:09 -06:00
282 lines
7.1 KiB
C++
282 lines
7.1 KiB
C++
#include "lzma.h"
|
|
|
|
#define _7ZIP_ST
|
|
|
|
#include "lib/LzmaDec.h"
|
|
#include "lib/LzmaEnc.h"
|
|
|
|
namespace Upp {
|
|
|
|
static voidpf lzma_alloc_new(ISzAllocPtr, size_t size) {
|
|
voidpf t = new byte[size];
|
|
return t;
|
|
}
|
|
|
|
static void lzma_free_new(ISzAllocPtr, void *address) {
|
|
if(!address)
|
|
return;
|
|
delete[] (byte *)address;
|
|
}
|
|
|
|
static ISzAlloc g_Alloc = { &lzma_alloc_new, &lzma_free_new };
|
|
|
|
struct IUppInStream {
|
|
ISeqInStream s;
|
|
Stream& in;
|
|
|
|
static SRes Read(const ISeqInStream *pp, void *buf, size_t *size) {
|
|
IUppInStream *p = (IUppInStream *)pp;
|
|
int64 h = (size_t)p->in.Get64(buf, *size);
|
|
if(p->in.IsError() || h < 0) {
|
|
*size = 0;
|
|
return SZ_ERROR_READ;
|
|
}
|
|
*size = (size_t)h;
|
|
return SZ_OK;
|
|
}
|
|
|
|
IUppInStream(Stream& in) : in(in) {
|
|
s.Read = Read;
|
|
}
|
|
};
|
|
|
|
struct IUppOutStream {
|
|
ISeqOutStream s;
|
|
Stream& out;
|
|
int64 len;
|
|
|
|
static size_t Write(const ISeqOutStream *pp, const void *buf, size_t size) {
|
|
IUppOutStream *p = (IUppOutStream *)pp;
|
|
p->out.Put64(buf, size);
|
|
p->len += size;
|
|
return p->out.IsError() ? -1 : size;
|
|
}
|
|
|
|
IUppOutStream(Stream& out) : out(out) {
|
|
s.Write = Write;
|
|
len = 0;
|
|
}
|
|
};
|
|
|
|
#define IN_BUF_SIZE (1 << 16)
|
|
#define OUT_BUF_SIZE (1 << 16)
|
|
|
|
static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 unpackSize, Gate2<int64, int64> progress)
|
|
{
|
|
int thereIsSize = (unpackSize != (UInt64)(Int64)-1);
|
|
Byte inBuf[IN_BUF_SIZE];
|
|
Byte outBuf[OUT_BUF_SIZE];
|
|
size_t inPos = 0, inSize = 0, outPos = 0;
|
|
LzmaDec_Init(state);
|
|
uint64 todo = unpackSize;
|
|
for(;;) {
|
|
if(inPos == inSize) {
|
|
inSize = IN_BUF_SIZE;
|
|
RINOK(inStream->Read(inStream, inBuf, &inSize));
|
|
inPos = 0;
|
|
}
|
|
SRes res;
|
|
SizeT inProcessed = inSize - inPos;
|
|
SizeT outProcessed = OUT_BUF_SIZE - outPos;
|
|
ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
|
|
ELzmaStatus status;
|
|
if(thereIsSize && outProcessed > unpackSize)
|
|
{
|
|
outProcessed = (SizeT)unpackSize;
|
|
finishMode = LZMA_FINISH_END;
|
|
}
|
|
|
|
res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
|
|
inBuf + inPos, &inProcessed, finishMode, &status);
|
|
inPos += inProcessed;
|
|
outPos += outProcessed;
|
|
unpackSize -= outProcessed;
|
|
|
|
if(progress(inPos, todo))
|
|
return SZ_ERROR_WRITE;
|
|
|
|
if(outStream)
|
|
if(outStream->Write(outStream, outBuf, outPos) != outPos)
|
|
return SZ_ERROR_WRITE;
|
|
|
|
outPos = 0;
|
|
if(res != SZ_OK || thereIsSize && unpackSize == 0)
|
|
return res;
|
|
|
|
if(inProcessed == 0 && outProcessed == 0) {
|
|
if(thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
|
|
return SZ_ERROR_DATA;
|
|
return res;
|
|
}
|
|
}
|
|
}
|
|
|
|
static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream, Gate2<int64, int64> progress)
|
|
{
|
|
UInt64 unpackSize;
|
|
int i;
|
|
SRes res = 0;
|
|
|
|
CLzmaDec state;
|
|
|
|
/* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
|
|
unsigned char header[LZMA_PROPS_SIZE + 8];
|
|
|
|
/* Read and parse header */
|
|
IUppInStream *is = (IUppInStream *)inStream;
|
|
if(is->in.Get(header, sizeof(header)) != sizeof(header))
|
|
return SZ_ERROR_READ;
|
|
|
|
unpackSize = 0;
|
|
for(i = 0; i < 8; i++)
|
|
unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8);
|
|
|
|
LzmaDec_Construct(&state);
|
|
RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc));
|
|
res = Decode2(&state, outStream, inStream, unpackSize, progress);
|
|
LzmaDec_Free(&state, &g_Alloc);
|
|
return res;
|
|
}
|
|
|
|
struct LUppProgress {
|
|
ICompressProgress s;
|
|
Gate2<int64, int64> progress;
|
|
int64 total;
|
|
|
|
static SRes Progress(const ICompressProgress *pp, UInt64 inSize, UInt64)
|
|
{
|
|
LUppProgress *p = (LUppProgress *)pp;
|
|
return p->progress(inSize, p->total);
|
|
}
|
|
|
|
LUppProgress() { s.Progress = Progress; }
|
|
};
|
|
|
|
static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, ICompressProgress *pg, int lvl)
|
|
{
|
|
CLzmaEncHandle enc;
|
|
SRes res;
|
|
CLzmaEncProps props;
|
|
|
|
enc = LzmaEnc_Create(&g_Alloc);
|
|
if (enc == 0)
|
|
return SZ_ERROR_MEM;
|
|
|
|
LzmaEncProps_Init(&props);
|
|
props.level = lvl;
|
|
res = LzmaEnc_SetProps(enc, &props);
|
|
|
|
if(res == SZ_OK) {
|
|
Byte header[LZMA_PROPS_SIZE + 8];
|
|
size_t headerSize = LZMA_PROPS_SIZE;
|
|
int i;
|
|
res = LzmaEnc_WriteProperties(enc, header, &headerSize);
|
|
for(i = 0; i < 8; i++)
|
|
header[headerSize++] = (Byte)(fileSize >> (8 * i));
|
|
if(outStream->Write(outStream, header, headerSize) != headerSize)
|
|
res = SZ_ERROR_WRITE;
|
|
else {
|
|
if(res == SZ_OK)
|
|
res = LzmaEnc_Encode(enc, outStream, inStream, pg, &g_Alloc, &g_Alloc);
|
|
}
|
|
}
|
|
LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
|
|
return res;
|
|
}
|
|
|
|
int64 LZMACompress(Stream& out, Stream& in, int64 size, Gate2<int64, int64> progress, int lvl)
|
|
{
|
|
IUppInStream lin(in);
|
|
IUppOutStream lout(out);
|
|
LUppProgress pg;
|
|
pg.progress = progress;
|
|
pg.total = size;
|
|
return Encode(&lout.s, &lin.s, size, &pg.s, lvl) == SZ_OK
|
|
&& !in.IsError() && !out.IsError() ? lout.len : -1;
|
|
}
|
|
|
|
int64 LZMACompress(Stream& out, Stream& in, Gate2<int64, int64> progress, int lvl)
|
|
{
|
|
return LZMACompress(out, in, in.GetLeft(), progress, lvl);
|
|
}
|
|
|
|
String LZMACompress(const void *data, int64 len, Gate2<int64, int64> progress, int lvl)
|
|
{
|
|
StringStream out;
|
|
MemReadStream in(data, len);
|
|
if(LZMACompress(out, in, len, progress, lvl) >= 0)
|
|
return out;
|
|
return String::GetVoid();
|
|
}
|
|
|
|
String LZMACompress(const String& s, Gate2<int64, int64> progress, int lvl)
|
|
{
|
|
return LZMACompress(~s, s.GetLength(), progress, lvl);
|
|
}
|
|
|
|
int64 LZMADecompress(Stream& out, Stream& in, Gate2<int64, int64> progress)
|
|
{
|
|
IUppInStream lin(in);
|
|
IUppOutStream lout(out);
|
|
return Decode(&lout.s, &lin.s, progress) == SZ_OK && !in.IsError() && !out.IsError() ? lout.len : -1;
|
|
}
|
|
|
|
String LZMADecompress(const void *data, int64 len, Gate2<int64, int64> progress)
|
|
{
|
|
StringStream out;
|
|
MemReadStream in(data, len);
|
|
if(LZMADecompress(out, in, progress) >= 0)
|
|
return out;
|
|
return String::GetVoid();
|
|
}
|
|
|
|
String LZMADecompress(const String& s, Gate2<int64, int64> progress)
|
|
{
|
|
return LZMADecompress(~s, s.GetLength(), progress);
|
|
}
|
|
|
|
bool LZMACompressFile(const char *dstfile, const char *srcfile, Gate2<int64, int64> progress, int lvl)
|
|
{
|
|
FileIn in(srcfile);
|
|
if(!in)
|
|
return false;
|
|
FileOut out(dstfile);
|
|
if(!out)
|
|
return false;
|
|
if(LZMACompress(out, in, (int)in.GetLeft(), progress, lvl) < 0)
|
|
return false;
|
|
out.Close();
|
|
return !out.IsError();
|
|
}
|
|
|
|
bool LZMACompressFile(const char *srcfile, Gate2<int64, int64> progress, int lvl)
|
|
{
|
|
String dstfile = String(srcfile) + ".lzma";
|
|
return LZMACompressFile(dstfile, srcfile, progress, lvl);
|
|
}
|
|
|
|
bool LZMADecompressFile(const char *dstfile, const char *srcfile, Gate2<int64, int64> progress)
|
|
{
|
|
FileIn in(srcfile);
|
|
if(!in)
|
|
return false;
|
|
FileOut out(dstfile);
|
|
if(!out)
|
|
return false;
|
|
if(LZMADecompress(out, in, progress) < 0)
|
|
return false;
|
|
out.Close();
|
|
return !out.IsError();
|
|
}
|
|
|
|
bool LZMADecompressFile(const char *srcfile, Gate2<int64, int64> progress)
|
|
{
|
|
String dstfile = srcfile;
|
|
if(dstfile.EndsWith(".lzma"))
|
|
dstfile.Trim(dstfile.GetLength() - 5);
|
|
else
|
|
return false;
|
|
return LZMADecompressFile(dstfile, srcfile, progress);
|
|
}
|
|
|
|
}
|