mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-05-16 06:05:58 -06:00
219 lines
3.9 KiB
C++
219 lines
3.9 KiB
C++
#include "lz4.h"
|
|
|
|
#define LLOG(x) // LOG(x)
|
|
|
|
namespace Upp {
|
|
|
|
void LZ4DecompressStream::Init()
|
|
{
|
|
for(int i = 0; i < 16; i++)
|
|
wb[i].Clear();
|
|
ii = 0;
|
|
count = 0;
|
|
dlen = 0;
|
|
pos = 0;
|
|
eof = false;
|
|
static byte h;
|
|
ptr = rdlim = buffer = &h;
|
|
xxh.Reset();
|
|
ClearError();
|
|
}
|
|
|
|
bool LZ4DecompressStream::Open(Stream& in_)
|
|
{
|
|
Init();
|
|
|
|
in = &in_;
|
|
String header_data = in->Get(7);
|
|
if(header_data.GetCount() < 7) {
|
|
SetError();
|
|
return false;
|
|
}
|
|
|
|
if(Peek32le(~header_data) != LZ4F_MAGIC) {
|
|
SetError();
|
|
return false;
|
|
}
|
|
lz4hdr = header_data[4];
|
|
if((lz4hdr & LZ4F_VERSIONMASK) != LZ4F_VERSION) {
|
|
SetError();
|
|
return false;
|
|
}
|
|
if(!(lz4hdr & LZ4F_BLOCKINDEPENDENCE)) { // dependent blocks not supported
|
|
SetError();
|
|
return false;
|
|
}
|
|
maxblock = header_data[5];
|
|
maxblock = decode(maxblock & LZ4F_MAXSIZEMASK,
|
|
LZ4F_MAXSIZE_64KB, 1024 * 64,
|
|
LZ4F_MAXSIZE_256KB, 1024 * 256,
|
|
LZ4F_MAXSIZE_1024KB, 1024 * 1024,
|
|
LZ4F_MAXSIZE_4096KB, 1024 * 4096,
|
|
-1);
|
|
if(maxblock < 0) {
|
|
SetError();
|
|
return false;
|
|
}
|
|
|
|
if((lz4hdr & LZ4F_CONTENTSIZE) && in->Get(8).GetCount() != 8) {
|
|
SetError();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool LZ4DecompressStream::Next()
|
|
{
|
|
pos += ptr - buffer;
|
|
ptr = rdlim = buffer;
|
|
if(ii < count) {
|
|
ptr = (byte *)~wb[ii].d;
|
|
Stream::buffer = ptr;
|
|
rdlim = ptr + wb[ii].dlen;
|
|
ii++;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
void LZ4DecompressStream::Fetch()
|
|
{
|
|
if(Next())
|
|
return;
|
|
if(eof)
|
|
return;
|
|
CoWork co;
|
|
bool error = false;
|
|
bool last = false;
|
|
ii = 0;
|
|
count = concurrent ? 16 : 1;
|
|
for(int i = 0; i < count; i++) {
|
|
Workblock& t = wb[i];
|
|
int blksz = in->Get32le();
|
|
if(blksz == 0) { // This is EOF
|
|
last = true;
|
|
count = i;
|
|
break;
|
|
}
|
|
t.clen = blksz & 0x7fffffff;
|
|
if(t.clen > maxblock) {
|
|
SetError();
|
|
return;
|
|
}
|
|
if(!t.c) {
|
|
t.c.Alloc(maxblock);
|
|
t.d.Alloc(maxblock);
|
|
}
|
|
if(blksz & 0x80000000) { // block is not compressed
|
|
t.dlen = t.clen;
|
|
if(!in->GetAll(~t.d, t.clen)) {
|
|
SetError();
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
if(!in->GetAll(~t.c, t.clen)) {
|
|
SetError();
|
|
return;
|
|
}
|
|
if(concurrent)
|
|
co & [=, &error] {
|
|
Workblock& t = wb[i];
|
|
t.dlen = LZ4_decompress_safe(~t.c, ~t.d, t.clen, maxblock);
|
|
CoWork::FinLock();
|
|
if(t.dlen < 0)
|
|
error = true;
|
|
};
|
|
else {
|
|
t.dlen = LZ4_decompress_safe(~t.c, ~t.d, t.clen, maxblock);
|
|
if(t.dlen < 0)
|
|
error = true;
|
|
}
|
|
}
|
|
if(lz4hdr & LZ4F_BLOCKCHECKSUM)
|
|
in->Get32le(); // just skip it
|
|
}
|
|
if(concurrent)
|
|
co.Finish();
|
|
if(error)
|
|
SetError();
|
|
else {
|
|
for(int i = 0; i < count; i++)
|
|
xxh.Put(wb[i].d, wb[i].dlen);
|
|
if(last) {
|
|
if(in->Get32le() != xxh.Finish())
|
|
SetError();
|
|
eof = true;
|
|
}
|
|
Next();
|
|
}
|
|
}
|
|
|
|
bool LZ4DecompressStream::IsOpen() const
|
|
{
|
|
return in->IsOpen() && !IsError();
|
|
}
|
|
|
|
int LZ4DecompressStream::_Term()
|
|
{
|
|
if(Ended())
|
|
return -1;
|
|
Fetch();
|
|
return ptr == rdlim ? -1 : *ptr;
|
|
}
|
|
|
|
int LZ4DecompressStream::_Get()
|
|
{
|
|
if(Ended())
|
|
return -1;
|
|
Fetch();
|
|
return ptr == rdlim ? -1 : *ptr++;
|
|
}
|
|
|
|
dword LZ4DecompressStream::_Get(void *data, dword size)
|
|
{
|
|
byte *t = (byte *)data;
|
|
while(size) {
|
|
if(Ended())
|
|
break;
|
|
dword n = dword(rdlim - ptr);
|
|
if(size < n) {
|
|
memcpy(t, ptr, size);
|
|
t += size;
|
|
ptr += size;
|
|
break;
|
|
}
|
|
else {
|
|
memcpy(t, ptr, n);
|
|
t += n;
|
|
size -= n;
|
|
ptr = rdlim;
|
|
Fetch();
|
|
}
|
|
}
|
|
|
|
return dword(t - (byte *)data);
|
|
}
|
|
|
|
LZ4DecompressStream::LZ4DecompressStream()
|
|
{
|
|
style = STRM_READ|STRM_LOADING;
|
|
in = NULL;
|
|
concurrent = false;
|
|
}
|
|
|
|
LZ4DecompressStream::~LZ4DecompressStream()
|
|
{
|
|
}
|
|
|
|
bool IsLZ4(Stream& s)
|
|
{
|
|
int64 pos = s.GetPos();
|
|
bool b = s.Get32le() == LZ4F_MAGIC;
|
|
s.Seek(pos);
|
|
return b;
|
|
}
|
|
|
|
};
|