From 8afdf5affa4aa1cc312a8db37bcd1782dc226e70 Mon Sep 17 00:00:00 2001 From: Carsten Teibes Date: Tue, 24 Sep 2024 01:47:02 +0200 Subject: [PATCH] Handle metadata for 0SC images Fix 13 --- src/io/file.cpp | 28 +++++++--------- src/jj1/scene/jj1sceneload.cpp | 10 +++++- src/util.cpp | 59 ++++++++++++++++++++++++++++++++++ src/util.h | 1 + 4 files changed, 80 insertions(+), 18 deletions(-) diff --git a/src/io/file.cpp b/src/io/file.cpp index cc8515b..e462e99 100644 --- a/src/io/file.cpp +++ b/src/io/file.cpp @@ -328,29 +328,23 @@ unsigned char* File::loadRLE (int length, bool checkSize) { int pos = 0; while (pos < length) { + unsigned char code = loadChar(); + unsigned char amount = code & 127; - int rle = loadChar(); - - if (rle & 128) { - - int byte = loadChar(); - int amount = rle & 127; + if (code & 128) { + unsigned char value = loadChar(); if (pos + amount >= length) break; - memset(buffer + pos, byte, amount); + memset(buffer + pos, value, amount); pos += amount; + } else if (amount) { + if (pos + amount >= length) break; - } else if (rle) { - - if (pos + rle >= length) break; - - fread(buffer + pos, 1, rle, file); - - pos += rle; - - } else buffer[pos++] = loadChar(); - + fread(buffer + pos, 1, amount, file); + pos += amount; + } else + buffer[pos++] = loadChar(); } if (checkSize) { diff --git a/src/jj1/scene/jj1sceneload.cpp b/src/jj1/scene/jj1sceneload.cpp index 3cb199e..8c8cd73 100644 --- a/src/jj1/scene/jj1sceneload.cpp +++ b/src/jj1/scene/jj1sceneload.cpp @@ -469,7 +469,15 @@ void JJ1Scene::loadData (File *f) { else height = f->loadShort(SH); images = new JJ1SceneImage(images); - images->image = f->loadSurface(width, height, false); + if (type == 5 || type == 6) { + f->seek(-5, false); // account for metadata 2 + 2 + unsigned char* pixels = unpackRLE(f->loadBlock(dataLen), dataLen, width * height + 4); + images->image = createSurface(pixels + 4, width, height); + delete[] pixels; + } else { + images->image = f->loadSurface(width, height, false); + } + images->id = loop; } diff --git a/src/util.cpp b/src/util.cpp index d35cc31..a8db422 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -27,6 +27,7 @@ #include "util.h" #include "io/file.h" +#include "io/log.h" #include @@ -298,3 +299,61 @@ fixed fCos (fixed angle) { return sinLut[(angle + 256) & 1023]; } + + +/** + * Unpack a block of RLE compressed data. + * + * @param data Buffer containing compressed data + * @param size The length of the compressed block + * @param outSize The length of the uncompressed block + * + * @return Buffer containing the uncompressed data + */ +unsigned char* unpackRLE (unsigned char* data, unsigned int size, unsigned int outSize) { + unsigned char* buffer = new unsigned char[outSize]; + + unsigned int posIn = 0, posOut = 0; + while (posIn < size) { + unsigned char code = data[posIn]; + unsigned char amount = code & 127; + + if (code & 128) { // repeat + unsigned char value = data[posIn+1]; + + if (posOut + amount >= outSize) { + LOG_WARN("Exceeding write buffer while RLE unpacking."); + break; + } + + memset(buffer + posOut, value, amount); + + posIn += 2; + posOut += amount; + } else if (amount) { // copy + + if (posOut + amount >= outSize) { + LOG_WARN("Exceeding write buffer while RLE unpacking."); + break; + } + + memcpy(buffer + posOut, data + posIn + 1, amount); + + posIn += amount + 1; + posOut += amount; + } else { // end marker + buffer[posOut++] = data[posIn+1]; + posIn += 2; + + //LOG_MAX("End marker found while RLE unpacking."); + break; + } + } + + if(size != posIn || outSize != posOut) { + LOG_DEBUG("RLE block has incorrect size: in %d/%d out %d/%d", size, posIn, outSize, posOut); + } + + delete[] data; + return buffer; +} diff --git a/src/util.h b/src/util.h index 29ada41..945d2a7 100644 --- a/src/util.h +++ b/src/util.h @@ -46,5 +46,6 @@ void uppercaseString (char *string); void camelcaseString (char *string); fixed fSin (fixed angle); fixed fCos (fixed angle); +unsigned char* unpackRLE (unsigned char* data, unsigned int size, unsigned int outSize); #endif