// Entpacker für das "Backwards LZ"-Format, mit dem Nintendo die .code von // Systemmodulen komprimiert. Luma3DS wendet code.ips-Patches auf die // ENTPACKTE .code an, deshalb müssen wir genauso rechnen. #include #include "blz.h" static u32 read32(const u8 *p) { return p[0] | (p[1] << 8) | (p[2] << 16) | ((u32)p[3] << 24); } bool blz_looks_compressed(const u8 *buf, u32 size) { if (size < 8) return false; u32 enc = read32(buf + size - 8); u32 add = read32(buf + size - 4); u32 hdr = enc >> 24; u32 enclen = enc & 0xFFFFFF; return hdr >= 8 && hdr <= 0x10 && enclen >= hdr && enclen <= size && add > 0 && add < 0x1000000; } u32 blz_decompressed_size(const u8 *buf, u32 size) { return size + read32(buf + size - 4); } // buf muss mindestens blz_decompressed_size() Bytes groß sein. // Daten liegen am Anfang von buf, es wird rückwärts in-place entpackt. bool blz_decompress(u8 *buf, u32 size) { u32 enc = read32(buf + size - 8); u32 hdr = enc >> 24; u32 enclen = enc & 0xFFFFFF; u32 outsize = blz_decompressed_size(buf, size); u8 *src = buf + size - hdr; u8 *srcEnd = buf + size - enclen; u8 *dst = buf + outsize; while (src > srcEnd) { u8 flags = *--src; for (int i = 0; i < 8 && src > srcEnd; i++, flags <<= 1) { if (flags & 0x80) { if (src - 2 < buf) return false; u8 hi = *--src; u8 lo = *--src; u32 len = (hi >> 4) + 3; u32 disp = (((hi & 0x0F) << 8) | lo) + 3; for (u32 j = 0; j < len; j++) { if (dst - 1 < buf || dst - 1 + disp >= buf + outsize) return false; dst--; *dst = dst[disp]; } } else { if (dst - 1 < buf) return false; *--dst = *--src; } } } return true; }