#include "common.hh" #include "decompress.hh" std::vector decompressLZ(char const* data, size_t len) { std::vector 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; }