REminiscence/decode_mac.cpp

149 lines
3.1 KiB
C++

#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "decode_mac.h"
#include "util.h"
uint8_t *decodeLzss(File &f, uint32_t &decodedSize) {
decodedSize = f.readUint32BE();
uint8_t *dst = (uint8_t *)malloc(decodedSize);
if (!dst) {
warning("Failed to allocate %d bytes for LZSS", decodedSize);
return 0;
}
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) {
y += buf->y;
if (y >= 0 && y < buf->h) {
if (buf->xflip) {
x = w - 1 - x;
}
x += buf->x;
if (x >= 0 && x < buf->w) {
buf->setPixel(buf, x, y, color);
}
}
}
void decodeC103(const uint8_t *src, int w, int h, DecodeBuffer *buf) {
static const int kBits = 12;
static const int kMask = (1 << kBits) - 1;
int cursor = 0;
int bits = 1;
int count = 0;
int offset = 0;
uint8_t window[(1 << kBits)];
for (int y = 0; y < h; ++y) {
for (int x = 0; x < w; ++x) {
if (count == 0) {
int carry = bits & 1;
bits >>= 1;
if (bits == 0) {
bits = *src++;
if (carry) {
bits |= 0x100;
}
carry = bits & 1;
bits >>= 1;
}
if (!carry) {
const uint8_t color = *src++;
window[cursor] = color;
++cursor;
cursor &= kMask;
setPixel(x, y, w, h, color, buf);
continue;
}
offset = READ_BE_UINT16(src); src += 2;
count = 3 + (offset >> 12);
offset &= kMask;
offset = (cursor - offset - 1) & kMask;
}
const uint8_t color = window[offset++];
offset &= kMask;
window[cursor++] = color;
cursor &= kMask;
setPixel(x, y, w, h, color, buf);
--count;
}
}
}
void decodeC211(const uint8_t *src, 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) {
const uint8_t code = *src++;
if ((code & 0x80) != 0) {
++y;
x = 0;
}
int count = code & 0x1F;
if (count == 0) {
count = READ_BE_UINT16(src); src += 2;
}
if ((code & 0x40) == 0) {
if ((code & 0x20) == 0) {
if (count == 1) {
assert(sp > 0);
--stack[sp - 1].repeatCount;
if (stack[sp - 1].repeatCount >= 0) {
src = stack[sp - 1].ptr;
} else {
--sp;
}
} else {
assert(sp < ARRAYSIZE(stack));
stack[sp].ptr = src;
stack[sp].repeatCount = count - 1;
++sp;
}
} else {
x += count;
}
} else {
if ((code & 0x20) == 0) {
if (count == 1) {
return;
}
const uint8_t color = *src++;
for (int i = 0; i < count; ++i) {
setPixel(x++, y, w, h, color, buf);
}
} else {
for (int i = 0; i < count; ++i) {
setPixel(x++, y, w, h, *src++, buf);
}
}
}
}
}