ultimatepp/uppsrc/plugin/lzma/lzma.cpp
cxl 8ebdcbb0d5 uppsrc: NAMESPACE_UPP / END_UPP_NAMESPACE removed
git-svn-id: svn://ultimatepp.org/upp/trunk@10186 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2016-08-26 17:15:30 +00:00

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(void *, size_t size) {
voidpf t = new byte[size];
return t;
}
static void lzma_free_new(void *, 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(void *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(void *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(void *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);
}
}