83 lines
1.9 KiB
C++
83 lines
1.9 KiB
C++
#include "common.hh"
|
|
|
|
#include "decompress.hh"
|
|
|
|
std::vector<uint8_t> decompressLZ(uint8_t const* data, size_t len)
|
|
{
|
|
std::vector<uint8_t> ret;
|
|
|
|
size_t pos = 0;
|
|
while (pos < len) {
|
|
uint8_t b = *(data+pos++);
|
|
if (!((b&0xe0)==0xe0)) {
|
|
unsigned size = 0, replSize = 0;
|
|
unsigned replOfs = 0;
|
|
if (!(b&0x80)) {
|
|
if (pos >= len)
|
|
throw FormatException{"Compressed stream overrun"};
|
|
|
|
uint8_t ofs = *(data+pos++);
|
|
size = b&0x3;
|
|
|
|
replSize = ((b&0x1c)>>2) + 3;
|
|
replOfs = ((b&0x60)<<3)+ofs+1;
|
|
} else if (!(b&0x40)) {
|
|
if (pos+1 >= len)
|
|
throw FormatException{"Compressed stream overrun"};
|
|
|
|
uint8_t b1 = *(data+pos++);
|
|
uint8_t b2 = *(data+pos++);
|
|
|
|
size = (b1&0xc0)>>6;
|
|
|
|
replSize = (b&0x3f)+4;
|
|
replOfs = ((b1&0x3f)<<8)+b2+1;
|
|
} else if (!(b&0x20)) {
|
|
if (pos+2 >= len)
|
|
throw FormatException{"Compressed stream overrun"};
|
|
|
|
uint8_t b1 = *(data+pos++);
|
|
uint8_t b2 = *(data+pos++);
|
|
uint8_t b3 = *(data+pos++);
|
|
|
|
size = b&0x3;
|
|
|
|
replSize = b3+5+((b&0xc)<<6);
|
|
replOfs = ((b&0x10)<<12)+1+(b1<<8)+b2;
|
|
}
|
|
if (pos+size >= len)
|
|
throw FormatException{"Compressed stream overrun"};
|
|
std::copy(data+pos, data+pos+size,
|
|
std::back_inserter(ret));
|
|
pos += size;
|
|
|
|
if (replOfs > ret.size())
|
|
throw FormatException{"Replication offset exceeds buffer"};
|
|
unsigned start = ret.size()-replOfs;
|
|
for (unsigned i = 0;i < replSize;++i)
|
|
ret.push_back(ret[start+i]);
|
|
} else {
|
|
unsigned size = (b&0x1f)*4+4;
|
|
if (size > 0x70) {
|
|
if (pos+(b&0x3) > len)
|
|
throw FormatException{"Compressed stream overrun"};
|
|
std::copy(data+pos, data+pos+(b&0x3),
|
|
std::back_inserter(ret));
|
|
pos += (b&0x3);
|
|
#ifndef NDEBUG
|
|
if (pos < len)
|
|
printf("%lu unparsed bytes in compressed data\n", len-pos);
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
if (pos+size > len)
|
|
throw FormatException{"Compressed stream overrun"};
|
|
std::copy(data+pos, data+pos+size,
|
|
std::back_inserter(ret));
|
|
pos += size;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|