59 lines
1.9 KiB
C
59 lines
1.9 KiB
C
// 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 <string.h>
|
|
#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;
|
|
}
|