mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 23:00:42 -07:00
Initial commit for GitHub migration based on spice2x-25-03-03
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
#pragma once
|
||||
|
||||
#include <queue>
|
||||
#include <cstdint>
|
||||
|
||||
namespace acio2emu::detail {
|
||||
class InflateTransformer {
|
||||
private:
|
||||
std::queue<uint8_t> output_;
|
||||
|
||||
uint8_t flags_ = 0, flag_shift_ = 0;
|
||||
|
||||
uint8_t window_[85] = {};
|
||||
int window_offset_ = 81;
|
||||
|
||||
enum class inflateStep {
|
||||
readFlags,
|
||||
processFlags,
|
||||
copyStored,
|
||||
copyFromWindow,
|
||||
} step_ = inflateStep::readFlags;
|
||||
|
||||
void window_put_(uint8_t b) {
|
||||
window_[window_offset_++] = b;
|
||||
window_offset_ %= sizeof(window_);
|
||||
}
|
||||
|
||||
uint8_t window_get_(int offset) {
|
||||
return window_[offset % sizeof(window_)];
|
||||
}
|
||||
|
||||
public:
|
||||
void put(uint8_t b) {
|
||||
auto consumed = false;
|
||||
|
||||
while (true) {
|
||||
switch (step_) {
|
||||
case inflateStep::readFlags:
|
||||
if (consumed) {
|
||||
// need more data
|
||||
return;
|
||||
}
|
||||
consumed = true;
|
||||
|
||||
flags_ = b;
|
||||
flag_shift_ = 0;
|
||||
|
||||
step_ = inflateStep::processFlags;
|
||||
break;
|
||||
|
||||
case inflateStep::processFlags:
|
||||
// have we processed every flag?
|
||||
if (flag_shift_ > 6) {
|
||||
step_ = inflateStep::readFlags;
|
||||
break;
|
||||
}
|
||||
|
||||
if (flags_ & (1 << flag_shift_)) {
|
||||
flag_shift_++;
|
||||
|
||||
if (flags_ & (1 << flag_shift_)) {
|
||||
// emit 0xAA when both bits are set
|
||||
output_.push(0xAA);
|
||||
}
|
||||
else {
|
||||
// copy from the window when only the lower bit is set
|
||||
step_ = inflateStep::copyFromWindow;
|
||||
}
|
||||
}
|
||||
else {
|
||||
step_ = inflateStep::copyStored;
|
||||
}
|
||||
flag_shift_++;
|
||||
|
||||
break;
|
||||
|
||||
case inflateStep::copyFromWindow: {
|
||||
if (consumed) {
|
||||
// need more data
|
||||
return;
|
||||
}
|
||||
consumed = true;
|
||||
|
||||
// determine the match size, default is 2-bytes
|
||||
auto offset = b;
|
||||
auto size = 2;
|
||||
|
||||
if (offset >= 0xAA) {
|
||||
// 4-byte match
|
||||
size = 4;
|
||||
offset -= 0xAB;
|
||||
}
|
||||
else if (offset >= 0x55) {
|
||||
// 3-byte match
|
||||
size = 3;
|
||||
offset -= 0x55;
|
||||
}
|
||||
|
||||
for (auto i = 0; i < size; i ++) {
|
||||
auto cur = window_get_(offset + i);
|
||||
|
||||
window_put_(cur);
|
||||
output_.push(cur);
|
||||
}
|
||||
|
||||
// continue processing flags
|
||||
step_ = inflateStep::processFlags;
|
||||
break;
|
||||
}
|
||||
|
||||
case inflateStep::copyStored:
|
||||
if (consumed) {
|
||||
// need more data
|
||||
return;
|
||||
}
|
||||
consumed = true;
|
||||
|
||||
window_put_(b);
|
||||
output_.push(b);
|
||||
|
||||
// continue processing flags
|
||||
step_ = inflateStep::processFlags;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int get() {
|
||||
if (output_.empty()) {
|
||||
// output queue is empty
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto b = output_.front();
|
||||
output_.pop();
|
||||
|
||||
return b;
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user