REminiscence/decode_mac.cpp

142 lines
2.7 KiB
C++

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "decode_mac.h"
#include "file.h"
uint8_t *decodeLzss(File &f, uint32_t &decodedSize) {
decodedSize = f.readUint32BE();
uint8_t *dst = (uint8_t *)malloc(decodedSize);
uint32_t count = 0;
while (count < decodedSize) {
const int code = f.readByte();
for (int i = 0; i < 8 && count < decodedSize; ++i) {
if ((code & (1 << i)) == 0) {
dst[count++] = f.readByte();
} else {
int offset = f.readUint16BE();
const int len = (offset >> 12) + 3;
offset &= 0xFFF;
for (int j = 0; j < len; ++j) {
dst[count + j] = dst[count - offset - 1 + j];
}
count += len;
}
}
}
assert(count == decodedSize);
return dst;
}
static void setPixel(int x, int y, int w, int h, uint8_t color, DecodeBuffer *buf) {
buf->setPixel(buf, x, y, w, h, color);
}
void decodeC103(const uint8_t *a3, int w, int h, DecodeBuffer *buf) {
uint8_t d0;
int d3 = 0;
int d7 = 1;
int d6 = 0;
int d1 = 0;
static const uint32_t d5 = 0xFFF;
uint8_t a1[0x1000];
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
assert(d6 >= 0);
if (d6 == 0) {
int carry = d7 & 1;
d7 >>= 1;
if (d7 == 0) {
d7 = *a3++;
const int extended_bit = carry ? 0x80 : 0;
carry = d7 & 1;
d7 = extended_bit | (d7 >> 1);
}
if (!carry) {
d0 = *a3++;
a1[d3] = d0;
++d3;
d3 &= d5;
setPixel(x, y, w, h, d0, buf);
continue;
}
d1 = READ_BE_UINT16(a3); a3 += 2;
d6 = d1;
d1 &= d5;
++d1;
d1 = (d3 - d1) & d5;
d6 >>= 12;
d6 += 3;
}
d0 = a1[d1++];
d1 &= d5;
a1[d3++] = d0;
d3 &= d5;
setPixel(x, y, w, h, d0, buf);
--d6;
}
}
}
void decodeC211(const uint8_t *a3, int w, int h, DecodeBuffer *buf) {
struct {
const uint8_t *ptr;
int repeatCount;
} stack[512];
int y = 0;
int x = 0;
int sp = 0;
while (1) {
uint8_t d0 = *a3++;
if ((d0 & 0x80) != 0) {
++y;
x = 0;
}
int d1 = d0 & 0x1F;
if (d1 == 0) {
d1 = READ_BE_UINT16(a3); a3 += 2;
}
const int carry_set = (d0 & 0x40) != 0;
d0 <<= 2;
if (!carry_set) {
if ((d0 & 0x80) == 0) {
--d1;
if (d1 == 0) {
assert(sp > 0);
--stack[sp - 1].repeatCount;
if (stack[sp - 1].repeatCount >= 0) {
a3 = stack[sp - 1].ptr;
} else {
--sp;
}
} else {
assert(sp < ARRAYSIZE(stack));
stack[sp].ptr = a3;
stack[sp].repeatCount = d1;
++sp;
}
} else {
x += d1;
}
} else {
if ((d0 & 0x80) == 0) {
if (d1 == 1) {
return;
}
const uint8_t color = *a3++;
for (int i = 0; i < d1; ++i) {
setPixel(x++, y, w, h, color, buf);
}
} else {
for (int i = 0; i < d1; ++i) {
setPixel(x++, y, w, h, *a3++, buf);
}
}
}
}
}