diff --git a/Makefile.am b/Makefile.am
index 595de14..1bae97d 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -9,7 +9,7 @@ elf2nro_SOURCES = src/elf2nro.c src/elf64.h src/romfs.c src/filepath.c src/filep
elf2nso_SOURCES = src/elf2nso.c src/sha256.c src/sha256.h src/elf64.h src/elf_common.h
-elf2kip_SOURCES = src/elf2kip.c src/cJSON.c src/cJSON.h src/sha256.c src/sha256.h src/elf64.h src/elf_common.h
+elf2kip_SOURCES = src/elf2kip.c src/cJSON.c src/cJSON.h src/blz.c src/blz.h src/elf64.h src/elf_common.h
nacptool_SOURCES = src/nacptool.c
diff --git a/src/blz.c b/src/blz.c
new file mode 100644
index 0000000..118ff4e
--- /dev/null
+++ b/src/blz.c
@@ -0,0 +1,338 @@
+/*----------------------------------------------------------------------------*/
+/*-- blz.c - Bottom LZ coding for Nintendo GBA/DS --*/
+/*-- Copyright (C) 2011 CUE --*/
+/*-- --*/
+/*-- This program is free software: you can redistribute it and/or modify --*/
+/*-- it under the terms of the GNU General Public License as published by --*/
+/*-- the Free Software Foundation, either version 3 of the License, or --*/
+/*-- (at your option) any later version. --*/
+/*-- --*/
+/*-- This program is distributed in the hope that it will be useful, --*/
+/*-- but WITHOUT ANY WARRANTY; without even the implied warranty of --*/
+/*-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --*/
+/*-- GNU General Public License for more details. --*/
+/*-- --*/
+/*-- You should have received a copy of the GNU General Public License --*/
+/*-- along with this program. If not, see . --*/
+/*----------------------------------------------------------------------------*/
+
+/*----------------------------------------------------------------------------*/
+#include "blz.h"
+#include
+#include
+#include
+
+/*----------------------------------------------------------------------------*/
+#define CMD_DECODE 0x00 // decode
+#define CMD_ENCODE 0x01 // encode
+
+#define BLZ_SHIFT 1 // bits to shift
+#define BLZ_MASK 0x80 // bits to check:
+ // ((((1 << BLZ_SHIFT) - 1) << (8 - BLZ_SHIFT)
+
+#define BLZ_THRESHOLD 2 // max number of bytes to not encode
+#define BLZ_N 0x1002 // max offset ((1 << 12) + 2)
+#define BLZ_F 0x12 // max coded ((1 << 4) + BLZ_THRESHOLD)
+
+#define RAW_MINIM 0x00000000 // empty file, 0 bytes
+#define RAW_MAXIM 0x00FFFFFF // 3-bytes length, 16MB - 1
+
+#define BLZ_MINIM 0x00000004 // header only (empty RAW file)
+#define BLZ_MAXIM 0x01400000 // 0x0120000A, padded to 20MB:
+ // * length, RAW_MAXIM
+ // * flags, (RAW_MAXIM + 7) / 8
+ // * header, 11
+ // 0x00FFFFFF + 0x00200000 + 12 + padding
+
+/*----------------------------------------------------------------------------*/
+#define BREAK(text) { printf(text); return; }
+#define EXIT(text) { printf(text); exit(-1); }
+
+/*----------------------------------------------------------------------------*/
+u8 *Memory(int length, int size);
+
+u8 *BLZ_Code(u8 *raw_buffer, int raw_len, u32 *new_len, int best);
+void BLZ_Invert(u8 *buffer, int length);
+
+/*----------------------------------------------------------------------------*/
+u8 *Memory(int length, int size) {
+ u8 *fb;
+
+ fb = (u8 *) calloc(length * size, size);
+ if (fb == NULL) EXIT("\nMemory error\n");
+
+ return(fb);
+}
+
+/*----------------------------------------------------------------------------*/
+void BLZ_Decode(char *filename) {
+ // u8 *pak_buffer, *raw_buffer, *pak, *raw, *pak_end, *raw_end;
+ // u32 pak_len, raw_len, len, pos, inc_len, hdr_len, enc_len, dec_len;
+ // u8 flags, mask;
+
+ // printf("- decoding '%s'", filename);
+
+ // // pak_buffer = Load(filename, &pak_len, BLZ_MINIM, BLZ_MAXIM);
+
+ // inc_len = *(u32 *)(pak_buffer + pak_len - 4);
+ // if (!inc_len) {
+ // enc_len = 0;
+ // dec_len = pak_len - 4;
+ // pak_len = 0;
+ // raw_len = dec_len;
+ // } else {
+ // if (pak_len < 8) EXIT("File has a bad header\n");
+ // hdr_len = pak_buffer[pak_len - 5];
+ // if ((hdr_len < 0x08) || (hdr_len > 0x0B)) EXIT("Bad header length\n");
+ // if (pak_len <= hdr_len) EXIT("Bad length\n");
+ // enc_len = *(u32 *)(pak_buffer + pak_len - 8) & 0x00FFFFFF;
+ // dec_len = pak_len - enc_len;
+ // pak_len = enc_len - hdr_len;
+ // raw_len = dec_len + enc_len + inc_len;
+ // if (raw_len > RAW_MAXIM) EXIT("Bad decoded length\n");
+ // }
+
+ // raw_buffer = (u8 *) Memory(raw_len, sizeof(char));
+
+ // pak = pak_buffer;
+ // raw = raw_buffer;
+ // pak_end = pak_buffer + dec_len + pak_len;
+ // raw_end = raw_buffer + raw_len;
+
+ // for (len = 0; len < dec_len; len++) *(raw++) = *(pak++);
+
+ // BLZ_Invert(pak_buffer + dec_len, pak_len);
+
+ // mask = 0;
+
+ // while (raw < raw_end) {
+ // if (!(mask >>= BLZ_SHIFT)) {
+ // if (pak == pak_end) break;
+ // flags = *pak++;
+ // mask = BLZ_MASK;
+ // }
+
+ // if (!(flags & mask)) {
+ // if (pak == pak_end) break;
+ // *raw++ = *pak++;
+ // } else {
+ // if (pak + 1 >= pak_end) break;
+ // pos = *pak++ << 8;
+ // pos |= *pak++;
+ // len = (pos >> 12) + BLZ_THRESHOLD + 1;
+ // if (raw + len > raw_end) {
+ // printf(", WARNING: wrong decoded length!");
+ // len = raw_end - raw;
+ // }
+ // pos = (pos & 0xFFF) + 3;
+ // while (len--) *(raw++) = *(raw - pos);
+ // }
+ // }
+
+ // BLZ_Invert(raw_buffer + dec_len, raw_len - dec_len);
+
+ // raw_len = raw - raw_buffer;
+
+ // if (raw != raw_end) printf(", WARNING: unexpected end of encoded file!");
+
+ // // Save(filename, raw_buffer, raw_len);
+
+ // free(raw_buffer);
+ // free(pak_buffer);
+
+ // printf("\n");
+}
+
+u8 *Load(char *filename, u32 *length, int min, int max) {
+ FILE *fp;
+ int fs;
+ u8 *fb;
+
+ if ((fp = fopen(filename, "rb")) == NULL) EXIT("\nFile open error\n");
+ fseek(fp, 0, SEEK_END);
+ fs = ftell(fp);
+ fseek(fp, 0, SEEK_SET);
+ if ((fs < min) || (fs > max)) EXIT("\nFile size error\n");
+ fb = Memory(fs + 3, sizeof(char));
+ if (fread(fb, 1, fs, fp) != fs) EXIT("\nFile read error\n");
+ if (fclose(fp) == EOF) EXIT("\nFile close error\n");
+
+ *length = fs;
+
+ return(fb);
+}
+
+/*----------------------------------------------------------------------------*/
+u8* BLZ_Encode(char *filename, u32* pak_len, int mode) {
+ u8 *raw_buffer, *pak_buffer, *new_buffer;
+ u32 raw_len, new_len;
+
+ raw_buffer = Load(filename, &raw_len, RAW_MINIM, RAW_MAXIM);
+
+ pak_buffer = NULL;
+ *pak_len = BLZ_MAXIM + 1;
+
+ new_buffer = BLZ_Code(raw_buffer, raw_len, &new_len, mode);
+ if (new_len < *pak_len) {
+ if (pak_buffer != NULL) free(pak_buffer);
+ pak_buffer = new_buffer;
+ *pak_len = new_len;
+ }
+
+ return pak_buffer;
+}
+
+/*----------------------------------------------------------------------------*/
+u8 *BLZ_Code(u8 *raw_buffer, int raw_len, u32 *new_len, int best) {
+ u8 *pak_buffer, *pak, *raw, *raw_end, *flg = NULL, *tmp;
+ u32 pak_len, inc_len, hdr_len, enc_len, len, pos, max;
+ u32 len_best, pos_best = 0, len_next, pos_next, len_post, pos_post;
+ u32 pak_tmp, raw_tmp;
+ u8 mask;
+
+#define SEARCH(l,p) { \
+ l = BLZ_THRESHOLD; \
+ \
+ max = raw - raw_buffer >= BLZ_N ? BLZ_N : raw - raw_buffer; \
+ for (pos = 3; pos <= max; pos++) { \
+ for (len = 0; len < BLZ_F; len++) { \
+ if (raw + len == raw_end) break; \
+ if (len >= pos) break; \
+ if (*(raw + len) != *(raw + len - pos)) break; \
+ } \
+ \
+ if (len > l) { \
+ p = pos; \
+ if ((l = len) == BLZ_F) break; \
+ } \
+ } \
+}
+
+ pak_tmp = 0;
+ raw_tmp = raw_len;
+
+ pak_len = raw_len + ((raw_len + 7) / 8) + 15;
+ pak_buffer = (u8 *) Memory(pak_len, sizeof(char));
+
+ BLZ_Invert(raw_buffer, raw_len);
+
+ pak = pak_buffer;
+ raw = raw_buffer;
+ raw_end = raw_buffer + raw_len;
+
+ mask = 0;
+
+ while (raw < raw_end) {
+ if (!(mask >>= BLZ_SHIFT)) {
+ *(flg = pak++) = 0;
+ mask = BLZ_MASK;
+ }
+
+ SEARCH(len_best, pos_best);
+
+ // LZ-CUE optimization start
+ if (best) {
+ if (len_best > BLZ_THRESHOLD) {
+ if (raw + len_best < raw_end) {
+ raw += len_best;
+ SEARCH(len_next, pos_next);
+ raw -= len_best - 1;
+ SEARCH(len_post, pos_post);
+ raw--;
+
+ if (len_next <= BLZ_THRESHOLD) len_next = 1;
+ if (len_post <= BLZ_THRESHOLD) len_post = 1;
+
+ if (len_best + len_next <= 1 + len_post) len_best = 1;
+ }
+ }
+ }
+ // LZ-CUE optimization end
+
+ *flg <<= 1;
+ if (len_best > BLZ_THRESHOLD) {
+ raw += len_best;
+ *flg |= 1;
+ *pak++ = ((len_best - (BLZ_THRESHOLD+1)) << 4) | ((pos_best - 3) >> 8);
+ *pak++ = (pos_best - 3) & 0xFF;
+ } else {
+ *pak++ = *raw++;
+ }
+
+ if (pak - pak_buffer + raw_len - (raw - raw_buffer) < pak_tmp + raw_tmp) {
+ pak_tmp = pak - pak_buffer;
+ raw_tmp = raw_len - (raw - raw_buffer);
+ }
+ }
+
+ while (mask && (mask != 1)) {
+ mask >>= BLZ_SHIFT;
+ *flg <<= 1;
+ }
+
+ pak_len = pak - pak_buffer;
+
+ BLZ_Invert(raw_buffer, raw_len);
+ BLZ_Invert(pak_buffer, pak_len);
+
+ if (!pak_tmp || (raw_len + 4 < ((pak_tmp + raw_tmp + 3) & -4) + 8)) {
+ pak = pak_buffer;
+ raw = raw_buffer;
+ raw_end = raw_buffer + raw_len;
+
+ while (raw < raw_end) *pak++ = *raw++;
+
+ while ((pak - pak_buffer) & 3) *pak++ = 0;
+
+ *(u32 *)pak = 0; pak += 4;
+ } else {
+ tmp = (u8 *) Memory(raw_tmp + pak_tmp + 11, sizeof(char));
+
+ for (len = 0; len < raw_tmp; len++)
+ tmp[len] = raw_buffer[len];
+
+ for (len = 0; len < pak_tmp; len++)
+ tmp[raw_tmp + len] = pak_buffer[len + pak_len - pak_tmp];
+
+ pak = pak_buffer;
+ pak_buffer = tmp;
+
+ free(pak);
+
+ pak = pak_buffer + raw_tmp + pak_tmp;
+
+ enc_len = pak_tmp;
+ hdr_len = 12;
+ inc_len = raw_len - pak_tmp - raw_tmp;
+
+ while ((pak - pak_buffer) & 3) {
+ *pak++ = 0xFF;
+ hdr_len++;
+ }
+
+ *(u32 *)pak = enc_len + hdr_len; pak += 4;
+ *(u32 *)pak = hdr_len; pak += 4;
+ *(u32 *)pak = inc_len - hdr_len; pak += 4;
+ }
+
+ *new_len = pak - pak_buffer;
+
+ return(pak_buffer);
+}
+
+/*----------------------------------------------------------------------------*/
+void BLZ_Invert(u8 *buffer, int length) {
+ u8 *bottom, ch;
+
+ bottom = buffer + length - 1;
+
+ while (buffer < bottom) {
+ ch = *buffer;
+ *buffer++ = *bottom;
+ *bottom-- = ch;
+ }
+}
+
+/*----------------------------------------------------------------------------*/
+/*-- EOF Copyright (C) 2011 CUE --*/
+/*----------------------------------------------------------------------------*/
diff --git a/src/blz.h b/src/blz.h
new file mode 100644
index 0000000..8263889
--- /dev/null
+++ b/src/blz.h
@@ -0,0 +1,13 @@
+#pragma once
+
+#include
+
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+
+#define BLZ_NORMAL 0 // normal mode
+#define BLZ_BEST 1 // best mode
+
+u8 *BLZ_Code(u8 *raw_buffer, int raw_len, u32 *new_len, int best);
\ No newline at end of file
diff --git a/src/elf2kip.c b/src/elf2kip.c
index 05ff80a..a0fb083 100644
--- a/src/elf2kip.c
+++ b/src/elf2kip.c
@@ -6,6 +6,7 @@
#include
#include
#include "cJSON.h"
+#include "blz.h"
#include "elf64.h"
typedef uint64_t u64;
@@ -428,9 +429,7 @@ int main(int argc, char* argv[]) {
KipHeader kip_hdr = {0};
memcpy(kip_hdr.Magic, "KIP1", 4);
- /* TODO: Enable compression for each section. */
- /* TODO: kip_hdr.Flags = 0x1F; */
- kip_hdr.Flags = 0x18;
+ kip_hdr.Flags = 0x1F;
if (sizeof(KipHeader) != 0x100) {
fprintf(stderr, "Bad compile environment!\n");
@@ -474,9 +473,11 @@ int main(int argc, char* argv[]) {
Elf64_Phdr* phdrs = (Elf64_Phdr*) &elf[hdr->e_phoff];
size_t i, j = 0;
size_t file_off = 0;
+ size_t dst_off = 0;
size_t tmpsize;
uint8_t* buf[3];
+ uint8_t* cmp[3];
size_t FileOffsets[3];
for (i=0; i<4; i++) {
@@ -496,7 +497,7 @@ int main(int argc, char* argv[]) {
}
- kip_hdr.Segments[i].DstOff = file_off;
+ kip_hdr.Segments[i].DstOff = dst_off;
// .bss is special
if (i == 3) {
@@ -513,7 +514,6 @@ int main(int argc, char* argv[]) {
FileOffsets[i] = phdr->p_vaddr;
kip_hdr.Segments[i].DecompSz = (phdr->p_filesz + 0xFFF) & ~0xFFF;
- kip_hdr.Segments[i].CompSz = kip_hdr.Segments[i].DecompSz;
buf[i] = malloc(kip_hdr.Segments[i].DecompSz);
if (buf[i] == NULL) {
@@ -524,9 +524,11 @@ int main(int argc, char* argv[]) {
memset(buf[i], 0, kip_hdr.Segments[i].DecompSz);
memcpy(buf[i], &elf[phdr->p_offset], phdr->p_filesz);
+ cmp[i] = BLZ_Code(buf[i], phdr->p_filesz, &kip_hdr.Segments[i].CompSz, BLZ_BEST);
- file_off += kip_hdr.Segments[i].DecompSz;
- file_off = (file_off + 0xFFF) & ~0xFFF;
+ file_off += kip_hdr.Segments[i].CompSz;
+ dst_off += kip_hdr.Segments[i].DecompSz;
+ dst_off = (dst_off + 0xFFF) & ~0xFFF;
}
FILE* out = fopen(argv[3], "wb");
@@ -541,7 +543,7 @@ int main(int argc, char* argv[]) {
for (i=0; i<3; i++)
{
fseek(out, sizeof(kip_hdr) + kip_hdr.Segments[i].DstOff, SEEK_SET);
- fwrite(buf[i], kip_hdr.Segments[i].CompSz, 1, out);
+ fwrite(cmp[i], kip_hdr.Segments[i].CompSz, 1, out);
}
fseek(out, 0, SEEK_SET);