diff --git a/src/app/gfx/compression.cc b/src/app/gfx/compression.cc index 85aa901f..0891428e 100644 --- a/src/app/gfx/compression.cc +++ b/src/app/gfx/compression.cc @@ -735,6 +735,139 @@ uint8_t* Compress(uint8_t const* const src, int const oldsize, int* const size, return b2; } +uint8_t* Uncompress(uint8_t const* src, int* const size, + int const p_big_endian) { + unsigned char* b2 = (unsigned char*)malloc(1024); + + int bd = 0, bs = 1024; + + unsigned char a; + unsigned char b; + unsigned short c, d; + + for (;;) { + // retrieve a uchar from the buffer. + a = *(src++); + + // end the decompression routine if we encounter 0xff. + if (a == 0xff) break; + + // examine the top 3 bits of a. + b = (a >> 5); + + if (b == 7) // i.e. 0b 111 + { + // get bits 0b 0001 1100 + b = ((a >> 2) & 7); + + // get bits 0b 0000 0011, multiply by 256, OR with the next byte. + c = ((a & 0x0003) << 8); + c |= *(src++); + } else + // or get bits 0b 0001 1111 + c = (uint16_t)(a & 31); + + c++; + + if ((bd + c) > (bs - 512)) { + // need to increase the buffer size. + bs += 1024; + b2 = (uint8_t*)realloc(b2, bs); + } + + // 7 was handled, here we handle other decompression codes. + + switch (b) { + case 0: // 0b 000 + + // raw copy + + // copy info from the src buffer to our new buffer, + // at offset bd (which we'll be increasing; + memcpy(b2 + bd, src, c); + + // increment the src pointer accordingly. + src += c; + + bd += c; + + break; + + case 1: // 0b 001 + + // rle copy + + // make c duplicates of one byte, inc the src pointer. + memset(b2 + bd, *(src++), c); + + // increase the b2 offset. + bd += c; + + break; + + case 2: // 0b 010 + + // rle 16-bit alternating copy + + d = core::ldle16b(src); + + src += 2; + + while (c > 1) { + // copy that 16-bit number c/2 times into the b2 buffer. + core::stle16b(b2 + bd, d); + + bd += 2; + c -= 2; // hence c/2 + } + + if (c) // if there's a remainder of c/2, this handles it. + b2[bd++] = (char)d; + + break; + + case 3: // 0b 011 + + // incrementing copy + + // get the current src byte. + a = *(src++); + + while (c--) { + // increment that byte and copy to b2 in c iterations. + // e.g. a = 4, b2 will have 4,5,6,7,8... written to it. + b2[bd++] = a++; + } + + break; + + default: // 0b 100, 101, 110 + + // lz copy + + if (p_big_endian) { + d = (*src << 8) + src[1]; + } else { + d = core::ldle16b(src); + } + + while (c--) { + // copy from a different location in the buffer. + b2[bd++] = b2[d++]; + } + + src += 2; + } + } + + b2 = (unsigned char*)realloc(b2, bd); + + if (size) (*size) = bd; + + // return the unsigned char* buffer b2, which contains the uncompressed data. + return b2; +} + absl::StatusOr CompressGraphics(const uchar* data, const int pos, const int length) { return CompressV2(data, pos, length, kNintendoMode2); diff --git a/src/app/gfx/compression.h b/src/app/gfx/compression.h index 0e435d2c..28e20d61 100644 --- a/src/app/gfx/compression.h +++ b/src/app/gfx/compression.h @@ -15,8 +15,29 @@ namespace yaze { namespace app { namespace gfx { +const int D_NINTENDO_C_MODE1 = 0; +const int D_NINTENDO_C_MODE2 = 1; + +const int D_CMD_COPY = 0; +const int D_CMD_BYTE_REPEAT = 1; +const int D_CMD_WORD_REPEAT = 2; +const int D_CMD_BYTE_INC = 3; +const int D_CMD_COPY_EXISTING = 4; + +const int D_MAX_NORMAL_LENGTH = 32; +const int D_MAX_LENGTH = 1024; + +const int INITIAL_ALLOC_SIZE = 1024; + namespace lc_lz2 { +absl::StatusOr ZS_Compress(const std::vector& data, + const int start, const int length, + int mode = 1, bool check = false); + +absl::StatusOr ZS_CompressOverworld(const std::vector data, + const int pos, const int length); + constexpr int kCommandDirectCopy = 0; constexpr int kCommandByteFill = 1; constexpr int kCommandWordFill = 2; @@ -191,9 +212,13 @@ absl::StatusOr CompressV3(const std::vector& data, const int start, const int length, int mode = 1, bool check = false); +// Hyrule Magic uint8_t* Compress(uint8_t const* const src, int const oldsize, int* const size, int const flag); +uint8_t* Uncompress(uint8_t const* src, int* const size, + int const p_big_endian); + // Decompression std::string SetBuffer(const std::vector& data, int src_pos,