diff --git a/src/Compression.cc b/src/Compression.cc index 0a094f24..a340b8f5 100644 --- a/src/Compression.cc +++ b/src/Compression.cc @@ -13,6 +13,52 @@ using namespace std; +template +struct LZSSInterleavedWriter { + StringWriter w; + size_t buf_offset; + uint8_t next_control_bit; + uint8_t buf[(MaxDataBytesPerControlBit * 8) + 1]; + + LZSSInterleavedWriter() + : buf_offset(1), + next_control_bit(1) { + this->buf[0] = 0; + } + + void flush_if_ready() { + if (this->next_control_bit == 0) { + this->w.write(this->buf, this->buf_offset); + this->buf[0] = 0; + this->buf_offset = 1; + this->next_control_bit = 1; + } + } + + std::string&& close() { + if (this->buf_offset > 1 || this->next_control_bit != 1) { + this->w.write(this->buf, this->buf_offset); + } + return std::move(this->w.str()); + } + + void write_control(bool v) { + if (this->next_control_bit == 0) { + throw logic_error("write_control called with no space to write"); + } + if (v) { + this->buf[0] |= this->next_control_bit; + } + this->next_control_bit <<= 1; + } + void write_data(uint8_t v) { + this->buf[this->buf_offset++] = v; + } + size_t size() const { + return this->w.size() + this->buf_offset; + } +}; + PRSCompressor::PRSCompressor( size_t compression_level, function progress_fn) : compression_level(compression_level), @@ -469,54 +515,6 @@ void prs_disassemble(FILE* stream, const std::string& data) { // PRS, there is only one type of backreference. Also, there is no stop opcode; // the decompressor simply stops when there are no more input bytes to read. -// TODO: bc0_compress produces slightly larger output than Sega's compressor. -// Reverse-engineer their implementation and fix this. - -template -struct LZSSInterleavedWriter { - StringWriter w; - parray buf; - size_t buf_offset; - uint8_t next_control_bit; - - LZSSInterleavedWriter() - : buf(0), - buf_offset(1), - next_control_bit(1) {} - - void flush_if_ready() { - if (this->next_control_bit == 0) { - this->w.write(this->buf.data(), this->buf_offset); - this->buf[0] = 0; - this->buf_offset = 1; - this->next_control_bit = 1; - } - } - - std::string&& close() { - if (this->buf_offset > 1 || this->next_control_bit != 1) { - this->w.write(this->buf.data(), this->buf_offset); - } - return std::move(this->w.str()); - } - - void write_control(bool v) { - if (this->next_control_bit == 0) { - throw logic_error("write_control called with no space to write"); - } - if (v) { - this->buf[0] |= this->next_control_bit; - } - this->next_control_bit <<= 1; - } - void write_data(uint8_t v) { - this->buf[this->buf_offset++] = v; - } - size_t size() const { - return this->w.size() + this->buf_offset; - } -}; - string bc0_compress(const string& data, function progress_fn) { return bc0_compress(data.data(), data.size(), progress_fn); } @@ -569,7 +567,7 @@ string bc0_compress(const void* in_data_v, size_t in_size, function