summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAetias <aetias@outlook.com>2024-09-10 20:19:34 +0200
committerAetias <aetias@outlook.com>2024-09-10 20:19:34 +0200
commit191bc0938da7fabc56a9b405f83fcdb4d77dafeb (patch)
tree7afaaebf01d67a5a376eacd9ea5d447ea8c49bd2
parenta1fdc1b54634108a0959df824f093b3c6197d44b (diff)
Remove obsolete ROM tools
-rw-r--r--tools/compress/.gitignore2
-rw-r--r--tools/compress/Makefile22
-rw-r--r--tools/compress/main.c287
-rw-r--r--tools/rom/.gitignore4
-rw-r--r--tools/rom/Makefile29
-rw-r--r--tools/rom/build.c1020
-rw-r--r--tools/rom/extract.c395
-rw-r--r--tools/rom/files.h223
-rw-r--r--tools/rom/ph.h42
-rw-r--r--tools/rom/rom.h124
10 files changed, 0 insertions, 2148 deletions
diff --git a/tools/compress/.gitignore b/tools/compress/.gitignore
deleted file mode 100644
index b0512009..00000000
--- a/tools/compress/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-compress
-compress.exe
diff --git a/tools/compress/Makefile b/tools/compress/Makefile
deleted file mode 100644
index 8b42a0bb..00000000
--- a/tools/compress/Makefile
+++ /dev/null
@@ -1,22 +0,0 @@
-CC := gcc
-CFLAGS := -g
-
-ifneq ($(DEBUG),1)
- CFLAGS += -O2 -DNDEBUG
-endif
-
-ifeq ($(OS),Windows_NT)
- OUTFILE := compress.exe
-else
- OUTFILE := compress
-endif
-
-.PHONY: all clean
-
-all: $(OUTFILE)
-
-clean:
- rm -f $(OUTFILE)
-
-$(OUTFILE): main.c
- $(CC) $(CFLAGS) -o $(OUTFILE) main.c
diff --git a/tools/compress/main.c b/tools/compress/main.c
deleted file mode 100644
index 536ee520..00000000
--- a/tools/compress/main.c
+++ /dev/null
@@ -1,287 +0,0 @@
-// Compresses files using a backwards LZ77 algorithm.
-// This is used to compress code after linking so that the compressed code matches the base ROM.
-
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#define VERSION "1.0"
-
-#ifndef min
-# define min(a,b) ((a) < (b) ? (a) : (b))
-#endif
-
-#define WRITE16(buf,val) do { (buf)[0] = (val) & 0xFF; (buf)[1] = ((val) >> 8) & 0xFF; } while (0)
-#define WRITE24(buf,val) do { (buf)[0] = (val) & 0xFF; (buf)[1] = ((val) >> 8) & 0xFF; (buf)[2] = ((val) >> 16) & 0xFF; } while (0)
-#define WRITE32(buf,val) do { (buf)[0] = (val) & 0xFF; (buf)[1] = ((val) >> 8) & 0xFF; (buf)[2] = ((val) >> 16) & 0xFF; (buf)[3] = ((val) >> 24) & 0xFF; } while (0)
-#define READ16(buf) ((buf)[0] | ((buf)[1] << 8))
-#define READ24(buf) ((buf)[0] | ((buf)[1] << 8) | ((buf)[2] << 16))
-#define READ32(buf) ((buf)[0] | ((buf)[1] << 8) | ((buf)[2] << 16) | ((buf)[3] << 24))
-
-#define LEN_BITS 4
-#define DIST_BITS 12
-#define MIN_SUBSEQ 3
-
-#define LEN_MASK ((1 << (LEN_BITS)) - 1)
-#define DIST_MASK ((1 << (DIST_BITS)) - 1)
-
-#define MAX_SUBSEQ ((MIN_SUBSEQ) + LEN_MASK)
-#define LOOKAHEAD (1 << (DIST_BITS))
-
-typedef struct {
- uint8_t *pos;
- uint32_t totalBytesSaved;
- uint8_t flags;
-} BlockInfo;
-
-bool FindSubsequence(const uint8_t *buf, const uint8_t *start, const uint8_t *end, size_t *pLen, size_t *pDist) {
- size_t bestLen = 0;
- size_t bestDist = 0;
- size_t maxLookahead = min(LOOKAHEAD + MAX_SUBSEQ, end - buf - 1);
- for (size_t i = 0; i < maxLookahead; ++i) {
- const uint8_t *needle = buf;
- const uint8_t *haystack = buf + 1 + i;
- if (*needle != *haystack) continue;
- size_t len = 0;
- while (needle - len >= start && needle[-len] == haystack[-len] && haystack - len > buf && len < MAX_SUBSEQ) {
- ++len;
- }
- size_t dist = haystack - needle - MIN_SUBSEQ;
- if (len > bestLen && dist <= DIST_MASK) {
- bestLen = len;
- bestDist = dist;
- }
- }
- if (bestLen < MIN_SUBSEQ) return false;
- *pLen = bestLen;
- *pDist = bestDist;
- return true;
-}
-
-bool Compress(const uint8_t *src, uint8_t *dst, size_t size, uint8_t **pResult, size_t *pLen, size_t *pNumIdentical) {
- const uint8_t *end = src + size;
- const uint8_t *read = end;
- uint8_t *writeEnd = dst + size;
- uint8_t *write = writeEnd - 1;
- uint8_t *pFlags = write;
- uint8_t flags;
- size_t flagCount = 0;
- int32_t bytesSaved = 0;
- BlockInfo *blockInfos = malloc(((size + 7) / 8) * sizeof(BlockInfo));
- size_t numBlocks = 0;
- while (read > src) {
- flags <<= 1;
- size_t len, dist;
- if (FindSubsequence(read - 1, src, end, &len, &dist)) {
- // write length-distance pair
- size_t pair = (((len - MIN_SUBSEQ) & LEN_MASK) << DIST_BITS) | (dist & DIST_MASK);
- read -= len;
- write -= 2;
- WRITE16(write, pair);
- flags |= 1;
- bytesSaved += len - 2;
- } else {
- // write literal
- write -= 1;
- read -= 1;
- *write = *read;
- }
- flagCount++;
- if (flagCount == 8) {
- flagCount = 0;
- *pFlags = flags;
- bytesSaved -= 1;
- write -= 1;
- pFlags = write;
-
- blockInfos[numBlocks].pos = write;
- blockInfos[numBlocks].totalBytesSaved = bytesSaved;
- blockInfos[numBlocks].flags = flags;
- numBlocks++;
-
- flags = 0;
- }
- }
- if (flagCount != 0) {
- blockInfos[numBlocks].pos = write;
- blockInfos[numBlocks].totalBytesSaved = bytesSaved;
- numBlocks++;
-
- *pFlags = flags << (8 - flagCount);
- }
- else {
- write += 1;
- }
- size_t numIdentical = 0;
- for (int32_t i = 0; i < numBlocks - 1; ++i) {
- if (blockInfos[i].totalBytesSaved == bytesSaved) {
- size_t flagBytesSaved = 0;
- for (; i >= 0; --i, ++flagBytesSaved) {
- // Save more bytes by ignoring blocks that have no length-distance pairs in them
- if (blockInfos[i].flags != 0) break;
- }
- numIdentical = blockInfos[i].pos - write;
- write += 1;
-
- // See if it's possible to remove some chunks based on the number of flag bytes saved
- flags = blockInfos[i].flags;
- for (int32_t j = 0; j < 8 && flagBytesSaved > 0; ++j) {
- if ((flags & 0x80) != 0) {
- if (flagBytesSaved < 2) break;
- numIdentical += 2;
- flagBytesSaved -= 2;
- } else {
- numIdentical += 1;
- flagBytesSaved -= 1;
- }
- flags >>= 1;
- }
-
- memcpy(write, src, numIdentical);
- while (write[numIdentical] == read[numIdentical]) {
- numIdentical += 1;
- }
- break;
- }
- }
- free(blockInfos);
- *pResult = write;
- *pLen = writeEnd - write;
- *pNumIdentical = numIdentical;
- return true;
-}
-
-bool WriteFooter(FILE *fp, const char *fileName, bool addPadding, uint32_t compressedSize, uint32_t originalSize, uint32_t start, uint32_t numIdentical) {
- size_t padding = 0;
- if (addPadding) padding = (0x4 - (compressedSize & 0x3)) & 0x3;
- for (size_t i = 0; i < padding; ++i) fputc(0xFF, fp);
- compressedSize += padding + 8;
- uint32_t readOffset = padding + 8;
- uint32_t writeOffset = originalSize - compressedSize - start;
- compressedSize -= numIdentical;
- if (fwrite(&compressedSize, 3, 1, fp) != 1) {
- if (fp == stdout) fprintf(stderr, "Failed to write compressed size to stdout\n");
- else fprintf(stderr, "Failed to write compressed size to '%s'\n", fileName);
- return false;
- }
- if (fwrite(&readOffset, 1, 1, fp) != 1) {
- if (fp == stdout) fprintf(stderr, "Failed to write read offset to stdout\n");
- else fprintf(stderr, "Failed to write read offset to '%s'\n", fileName);
- return false;
- }
- if (fwrite(&writeOffset, 4, 1, fp) != 1) {
- if (fp == stdout) fprintf(stderr, "Failed to write write offset to stdout\n");
- else fprintf(stderr, "Failed to write write offset to '%s'\n", fileName);
- return false;
- }
- return true;
-}
-
-void PrintUsage(const char *program) {
- printf(
- "compress " VERSION "\n"
- "\n"
- "Usage: %s [-o OUTFILE] [-s START] [-p] -i INFILE\n"
- " -o OUTFILE\tWrites result to file instead of stdout\n"
- " -s START \tOffset to start compressing from\n"
- " -p \tPad compressed data to 4-alignment\n"
- " -i INFILE \tInput file to compress",
- program
- );
-}
-
-int main(int argc, const char **argv) {
- const char *program = argv[0];
- if (argc == 1) {
- PrintUsage(program);
- return 0;
- }
- const char *outFile = NULL;
- const char *inFile = NULL;
- int start = 0;
- bool padCompressedBlock = false;
- for (int i = 1; i < argc; ++i) {
- if (strcmp(argv[i], "-o") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected filename after -o\n");
- return 1;
- }
- outFile = argv[i];
- } else if (strcmp(argv[i], "-s") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected start offset after -s\n");
- return 1;
- }
- if (sscanf(argv[i], "%i", &start) != 1) {
- fprintf(stderr, "Invalid start offset '%s' could not be parsed\n", argv[i]);
- return 1;
- }
- } else if (strcmp(argv[i], "-p") == 0) {
- padCompressedBlock = true;
- } else if (strcmp(argv[i], "-i") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected filename after -i\n");
- return 1;
- }
- inFile = argv[i];
- } else {
- fprintf(stderr, "Unknown option '%s'\n", argv[i]);
- return 1;
- }
- }
- if (inFile == NULL) {
- PrintUsage(program);
- fprintf(stderr, "Please provide an input file to compress, see usage above.\n");
- return 1;
- }
-
- FILE *fpIn = fopen(inFile, "rb");
- if (fpIn == NULL) {
- fprintf(stderr, "Failed to open input file '%s'\n", inFile);
- return 1;
- }
- fseek(fpIn, 0, SEEK_END);
- size_t inSize = ftell(fpIn);
- uint8_t *buf = malloc(inSize);
- if (buf == NULL) {
- fprintf(stderr, "Failed to allocate input buffer for '%s'\n", inFile);
- return 1;
- }
- fseek(fpIn, 0, SEEK_SET);
- if (fread(buf, inSize, 1, fpIn) != 1) {
- fprintf(stderr, "Failed to read input file '%s'\n", inFile);
- return 1;
- }
- fclose(fpIn);
-
- FILE *fpOut = stdout;
- if (outFile != NULL) {
- fpOut = fopen(outFile, "wb");
- if (fpOut == NULL) {
- fprintf(stderr, "Failed to open output file '%s'\n", outFile);
- return 1;
- }
- }
- if (start > 0 && fwrite(buf, start, 1, fpOut) != 1) {
- if (fpOut == stdout) fprintf(stderr, "Failed to write uncompressed header to stdout\n");
- else fprintf(stderr, "Failed to write uncompressed header to '%s'\n", outFile);
- return 1;
- }
-
- uint8_t *outBuf = malloc(inSize - start);
- uint8_t *result;
- size_t resultLen, numIdentical;
- if (!Compress(buf + start, outBuf, inSize - start, &result, &resultLen, &numIdentical)) return 1;
- if (fwrite(result, resultLen, 1, fpIn) != 1) {
- if (fpOut == stdout) fprintf(stderr, "Failed to write compressed output to stdout\n");
- else fprintf(stderr, "Failed to write compressed output to '%s'\n", outFile);
- return 1;
- }
- if (!WriteFooter(fpOut, outFile, padCompressedBlock, resultLen, inSize, start, numIdentical)) return 1;
- free(outBuf);
-
- if (outFile != NULL) fclose(fpOut);
- free(buf);
-}
diff --git a/tools/rom/.gitignore b/tools/rom/.gitignore
deleted file mode 100644
index ee6c2dcd..00000000
--- a/tools/rom/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-extractrom
-extractrom.exe
-buildrom
-buildrom.exe
diff --git a/tools/rom/Makefile b/tools/rom/Makefile
deleted file mode 100644
index 201c69b0..00000000
--- a/tools/rom/Makefile
+++ /dev/null
@@ -1,29 +0,0 @@
-CC := gcc
-CFLAGS := -g -Wall -I../include
-
-ifneq ($(DEBUG),1)
- CFLAGS += -O2 -DNDEBUG
-endif
-
-ifeq ($(OS),Windows_NT)
- EXTRACTFILE := extractrom.exe
- BUILDFILE := buildrom.exe
-else
- EXTRACTFILE := extractrom
- BUILDFILE := buildrom
- CFLAGS += -fshort-wchar
-endif
-
-.PHONY: all clean
-
-all: $(EXTRACTFILE) $(BUILDFILE)
-
-clean:
- rm -f $(EXTRACTFILE)
- rm -f $(BUILDFILE)
-
-$(EXTRACTFILE): extract.c
- $(CC) $(CFLAGS) -o $(EXTRACTFILE) extract.c
-
-$(BUILDFILE): build.c
- $(CC) $(CFLAGS) -o $(BUILDFILE) build.c
diff --git a/tools/rom/build.c b/tools/rom/build.c
deleted file mode 100644
index 20eadb0b..00000000
--- a/tools/rom/build.c
+++ /dev/null
@@ -1,1020 +0,0 @@
-#include <assert.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "rom.h"
-#include "ph.h"
-#include "util.h"
-#include "files.h"
-
-#define VERSION "1.1.1"
-
-#define BUFFER_SIZE 1024 * 1024
-uint8_t *readBuffer = NULL;
-
-#define MAX_DIR_SIZE 256
-#define INITIAL_SUBTABLE_SIZE 1024 * 1024
-#define INITIAL_TABLE_SIZE 256
-#define MAX_OVERLAYS 128
-
-const uint8_t logo[] = {
- 0x24, 0xff, 0xae, 0x51, 0x69, 0x9a, 0xa2, 0x21, 0x3d, 0x84, 0x82, 0x0a, 0x84, 0xe4, 0x09, 0xad,
- 0x11, 0x24, 0x8b, 0x98, 0xc0, 0x81, 0x7f, 0x21, 0xa3, 0x52, 0xbe, 0x19, 0x93, 0x09, 0xce, 0x20,
- 0x10, 0x46, 0x4a, 0x4a, 0xf8, 0x27, 0x31, 0xec, 0x58, 0xc7, 0xe8, 0x33, 0x82, 0xe3, 0xce, 0xbf,
- 0x85, 0xf4, 0xdf, 0x94, 0xce, 0x4b, 0x09, 0xc1, 0x94, 0x56, 0x8a, 0xc0, 0x13, 0x72, 0xa7, 0xfc,
- 0x9f, 0x84, 0x4d, 0x73, 0xa3, 0xca, 0x9a, 0x61, 0x58, 0x97, 0xa3, 0x27, 0xfc, 0x03, 0x98, 0x76,
- 0x23, 0x1d, 0xc7, 0x61, 0x03, 0x04, 0xae, 0x56, 0xbf, 0x38, 0x84, 0x00, 0x40, 0xa7, 0x0e, 0xfd,
- 0xff, 0x52, 0xfe, 0x03, 0x6f, 0x95, 0x30, 0xf1, 0x97, 0xfb, 0xc0, 0x85, 0x60, 0xd6, 0x80, 0x25,
- 0xa9, 0x63, 0xbe, 0x03, 0x01, 0x4e, 0x38, 0xe2, 0xf9, 0xa2, 0x34, 0xff, 0xbb, 0x3e, 0x03, 0x44,
- 0x78, 0x00, 0x90, 0xcb, 0x88, 0x11, 0x3a, 0x94, 0x65, 0xc0, 0x7c, 0x63, 0x87, 0xf0, 0x3c, 0xaf,
- 0xd6, 0x25, 0xe4, 0x8b, 0x38, 0x0a, 0xac, 0x72, 0x21, 0xd4, 0xf8, 0x07,
-};
-
-uint16_t crcTable[0x100];
-void GenerateCrcTable() {
- uint16_t polynomial = 0xa001;
- for (size_t i = 0; i < 0x100; ++i) {
- uint16_t value = i;
- for (size_t j = 0; j < 8; ++j) {
- if (value & 1) value = polynomial ^ (value >> 1);
- else value >>= 1;
- }
- crcTable[i] = value;
- }
-}
-
-uint16_t Crc(const void *buf, size_t size) {
- uint16_t crc = 0xffff;
- const uint8_t *data = buf;
- for (size_t i = 0; i < size; ++i) {
- crc = crcTable[(crc & 0xff) ^ data[i]] ^ (crc >> 8);
- }
- return crc;
-}
-
-typedef struct {
- /* 0000 */ uint32_t subkeys[0x12];
- /* 0048 */ uint32_t sbox[4][0x100];
- /* 1048 */
-} Blowfish;
-Blowfish blowfish;
-
-uint32_t BlowfishF(size_t x) {
- uint32_t f;
- f = blowfish.sbox[0][(x >> 24) & 0xff];
- f += blowfish.sbox[1][(x >> 16) & 0xff];
- f ^= blowfish.sbox[2][(x >> 8) & 0xff];
- f += blowfish.sbox[3][x & 0xff];
- return f;
-}
-
-void BlowfishEncrypt(uint32_t *pLeft, uint32_t *pRight) {
- uint32_t tmp;
- uint32_t x = *pRight;
- uint32_t y = *pLeft;
- for (size_t i = 0; i < 0x10; ++i) {
- tmp = x ^ blowfish.subkeys[i];
- x = y ^ BlowfishF(tmp);
- y = tmp;
- }
- *pLeft = x ^ blowfish.subkeys[0x10];
- *pRight = y ^ blowfish.subkeys[0x11];
-}
-
-void BlowfishApplyCode(uint32_t code[3]) {
- BlowfishEncrypt(&code[1], &code[2]);
- BlowfishEncrypt(&code[0], &code[1]);
- for (size_t i = 0; i < 0x12; ++i) {
- uint32_t x = REVERSE32(code[i % 2]);
- blowfish.subkeys[i] ^= x;
- }
-
- uint32_t scratch0 = 0;
- uint32_t scratch1 = 0;
- for (size_t i = 0; i < 0x12; i += 2) {
- BlowfishEncrypt(&scratch0, &scratch1);
- blowfish.subkeys[i + 0] = scratch1;
- blowfish.subkeys[i + 1] = scratch0;
- }
- for (size_t i = 0; i < 4; ++i) {
- for (size_t j = 0; j < 0x100; j += 2) {
- BlowfishEncrypt(&scratch0, &scratch1);
- blowfish.sbox[i][j + 0] = scratch1;
- blowfish.sbox[i][j + 1] = scratch0;
- }
- }
-}
-
-bool BlowfishInit(const uint8_t *encKey, const Header *pHeader, size_t level) {
- memcpy(&blowfish, encKey, sizeof(blowfish));
-
- uint32_t code[3];
- memcpy(&code[0], pHeader->gamecode, sizeof(code[0]));
- code[1] = code[0] >> 1;
- code[2] = code[0] << 1;
- BlowfishApplyCode(code);
- if (level >= 2) BlowfishApplyCode(code);
- if (level >= 3) {
- code[1] <<= 1;
- code[2] >>= 1;
- BlowfishApplyCode(code);
- }
- return true;
-}
-
-void InitHeader(Header *pHeader, const BuildInfo *info) {
- memcpy(&pHeader->title, TITLE, sizeof(pHeader->title));
- memcpy(&pHeader->gamecode, GAMECODE_PREFIX, 3);
- pHeader->gamecode[3] = info->region;
- memcpy(&pHeader->makercode, "01", sizeof(pHeader->makercode));
-
- pHeader->unitcode = 0;
- pHeader->encSeedSelect = 0;
- pHeader->capacity = 0;
- memset(&pHeader->reserved0, 0, sizeof(pHeader->reserved0));
- pHeader->dsRegion = 0;
- pHeader->romVersion = 0;
- pHeader->autostart = 0;
-
- pHeader->arm9.offset = 0;
- pHeader->arm9.entry = 0;
- pHeader->arm9.baseAddr = 0;
- pHeader->arm9.size = 0;
-
- pHeader->arm7.offset = 0;
- pHeader->arm7.entry = 0x2380000;
- pHeader->arm7.baseAddr = 0x2380000;
- pHeader->arm7.size = 0;
-
- pHeader->fileNames.offset = 0;
- pHeader->fileNames.size = 0;
- pHeader->fileAllocs.offset = 0;
- pHeader->fileAllocs.size = 0;
- pHeader->arm9Overlays.offset = 0;
- pHeader->arm9Overlays.size = 0;
- pHeader->arm7Overlays.offset = 0;
- pHeader->arm7Overlays.size = 0;
-
- pHeader->normalCmdSetting = 0x00416657;
- pHeader->key1CmdSetting = 0x081808f8;
- pHeader->bannerOffset = 0;
- pHeader->secureAreaCrc = 0;
- pHeader->secureAreaDelay = 0x0d7e;
- pHeader->arm9AutoloadCallback = 0;
- pHeader->arm7AutoloadCallback = 0x2380158;
- pHeader->secureAreaDisable = 0;
- pHeader->romSize = 0;
- pHeader->headerSize = sizeof(Header);
- pHeader->autoloadBlockInfosOffset = 0;
- memset(&pHeader->reserved1, 0, sizeof(pHeader->reserved1));
- pHeader->romEnd = 0;
- pHeader->rwEnd = 0;
- memset(&pHeader->reserved2, 0, sizeof(pHeader->reserved2));
- memset(&pHeader->reserved3, 0, sizeof(pHeader->reserved3));
- memcpy(&pHeader->logo, logo, sizeof(pHeader->logo));
- pHeader->logoCrc = Crc(logo, sizeof(logo));
- pHeader->headerCrc = 0;
- pHeader->debugRomOffset = 0;
- pHeader->debugSize = 0;
- pHeader->debugRamAddr = 0;
- memset(&pHeader->reserved4, 0, sizeof(pHeader->reserved4));
- memset(&pHeader->reserved5, 0, sizeof(pHeader->reserved5));
- memset(&pHeader->reserved6, 0, sizeof(pHeader->reserved6));
- memset(&pHeader->reserved7, 0, sizeof(pHeader->reserved7));
-}
-
-typedef struct {
- uint32_t autoloadBlocksStart;
- uint32_t autoloadBlocksEnd;
- uint32_t autoloadCode;
- uint32_t bssStart;
- uint32_t bssEnd;
-} Arm9ModuleInfo;
-
-typedef struct {
- uint32_t autoloadCallback;
- uint32_t autoloadBlockInfos;
- uint32_t entryAddr;
- uint32_t baseAddr;
- Arm9ModuleInfo moduleInfo;
-} Arm9Metadata;
-
-bool LoadArm9Metadata(Arm9Metadata *pMetadata) {
- File file;
- if (!FileOpenRead(ARM9_METADATA_FILE, &file)) return false;
- if (FileRead(&file, pMetadata, sizeof(*pMetadata), 1) == 0) return false;
- FileClose(&file);
- return true;
-}
-
-// Reads an entire file into a newly allocated buffer and writes it to *pBuffer if successful.
-// If pFileSize != NULL, this function writes the file's size into *pFileSize.
-// The buffer can be freed with free().
-bool ReadFileAlloc(const char *filePath, uint8_t **pBuffer, uint32_t *pFileSize) {
- File file;
- if (!FileOpenRead(filePath, &file)) return false;
- size_t size = FileSize(&file);
-
- uint8_t *buffer = malloc(size);
- if (buffer == NULL) FATAL("Failed to allocate buffer for file '%s'\n", filePath);
- uint8_t *current = buffer;
- uint8_t *end = buffer + size;
-
- while (current < end) {
- size_t bytesRead = FileRead(&file, current, 1, BUFFER_SIZE);
- if (bytesRead == 0) return false;
- current += bytesRead;
- }
- FileClose(&file);
-
- *pBuffer = buffer;
- if (pFileSize != NULL) *pFileSize = size;
- return true;
-}
-
-bool AppendFile(File *rom, const char *filePath, size_t *pAddress, uint32_t *pFileSize) {
- assert(readBuffer != NULL);
-
- File file;
- if (!FileOpenRead(filePath, &file)) return false;
- size_t size = FileSize(&file);
-
- size_t bytesWritten = 0;
- while (bytesWritten < size) {
- size_t bytesRead = FileRead(&file, readBuffer, 1, BUFFER_SIZE);
- if (bytesRead == 0) return false;
- if (!FileWrite(rom, readBuffer, bytesRead, 1)) FATAL("Failed to write file '%s' to output ROM\n", filePath);
- bytesWritten += bytesRead;
- }
- FileClose(&file);
-
- *pAddress += size;
- if (pFileSize != NULL) *pFileSize = size;
- return true;
-}
-
-bool WriteArm9Program(File *rom, size_t *pAddress, uint32_t *pFileSize, uint32_t *pSecureArea, const Arm9Metadata *metadata) {
- size_t address = *pAddress;
-
- uint8_t *arm9;
- uint32_t fileSize;
- if (!ReadFileAlloc(ARM9_PROGRAM_FILE, &arm9, &fileSize)) return false;
-
- // Write module info, see spAutoloadBlockInfosStart in asm/main.s
- // This might seem unsafe since the ARM9 program is compressed, but the addresses we're writing to are in the secure area,
- // which is uncompressed.
-
- size_t offset = metadata->autoloadBlockInfos;
- // First five values, from spAutoloadBlockInfosStart to spBssEnd
- memcpy(&arm9[offset], &metadata->moduleInfo, sizeof(metadata->moduleInfo));
- offset += sizeof(metadata->moduleInfo);
- // Last value, sCompressedCodeEnd
- uint32_t compressedCodeEnd = 0x2000000 + fileSize;
- memcpy(&arm9[offset], &compressedCodeEnd, sizeof(compressedCodeEnd));
- offset += compressedCodeEnd;
-
- if (!FileWrite(rom, arm9, fileSize, 1)) FATAL("Failed to write ARM9 program\n");
- address += fileSize;
-
- memcpy(pSecureArea, arm9, SECURE_AREA_SIZE);
- free(arm9);
-
- *pAddress = address;
- *pFileSize = fileSize;
- return true;
-}
-
-bool Align(size_t alignment, File *rom, size_t *pAddress) {
- assert((alignment & (alignment - 1)) == 0);
-
- size_t mask = alignment - 1;
- size_t address = FileOffset(rom);
- size_t nextAddr = (address + mask) & ~mask;
- char padValue = 0xff;
- while (address < nextAddr) {
- if (!FileWrite(rom, &padValue, sizeof(padValue), 1)) FATAL("Failed to pad output ROM at address 0x%lx\n", address);
- address += sizeof(padValue);
- }
- *pAddress = address;
- return true;
-}
-
-bool WriteArm9OverlayTable(
- File *rom,
- size_t *pAddress,
- Header *pHeader,
- const char *overlayDataFile,
- OverlayEntry **pEntries,
- OverlayData **pData,
- size_t *pNumOverlays
-) {
- size_t address = *pAddress;
-
- File file;
- if (!FileOpenRead(ARM9_OVERLAY_TABLE_FILE, &file)) {
- FATAL("Failed to open ARM9 overlay table '" ARM9_OVERLAY_TABLE_FILE "'\n");
- }
- size_t tableSize = FileSize(&file);
- if (tableSize % sizeof(OverlayEntry) != 0) {
- FATAL("ARM9 overlay table has an invalid size (entries must be %ld bytes long)\n", sizeof(OverlayEntry));
- }
- size_t numOverlays = tableSize / sizeof(OverlayEntry);
-
- OverlayEntry *entries = malloc(tableSize);
- if (entries == NULL) FATAL("Failed to allocate array for ARM9 overlay table entries");
- if (FileRead(&file, entries, tableSize, 1) == 0) FATAL("Failed to read ARM9 overlay table '" ARM9_OVERLAY_TABLE_FILE "'\n");
- FileClose(&file);
-
- if (!FileOpenRead(overlayDataFile, &file)) FATAL("Failed to open ARM9 overlay data file '%s'\n", overlayDataFile);
- size_t dataSize = FileSize(&file);
- if (dataSize != numOverlays * sizeof(OverlayData)) {
- FATAL("ARM9 overlay data file has an invalid size (expected %ld overlays with %ld bytes each)\n", numOverlays, sizeof(OverlayData));
- }
-
- OverlayData *data = malloc(dataSize);
- if (data == NULL) FATAL("Failed to allocate array for ARM9 overlay data entries\n");
- if (FileRead(&file, data, dataSize, 1) == 0) FATAL("Failed to read ARM9 overlay data '%s'\n", overlayDataFile);
- FileClose(&file);
- for (size_t i = 0; i < numOverlays; ++i) {
- entries[i].fileId = data[i].fileId;
- }
-
- if (!FileWrite(rom, entries, tableSize, 1)) FATAL("Failed to write ARM9 overlay table\n");
-
- *pAddress = address;
- *pEntries = entries;
- *pData = data;
- *pNumOverlays = numOverlays;
- pHeader->arm9Overlays.size = tableSize;
- return true;
-}
-
-bool WriteArm9OverlayFiles(
- File *rom,
- size_t *pAddress,
- size_t numOverlays,
- FatEntry *fatEntries,
- OverlayEntry *table,
- const OverlayData *data
-) {
- size_t address = *pAddress;
- char fileName[32];
-
- if (!ChangeDir(OVERLAYS_SUBDIR)) return false;
-
- for (size_t ovNum = 0; ovNum < numOverlays; ++ovNum) {
- sprintf(fileName, "ov%02ld.lz", ovNum);
- if (!Align(512, rom, &address)) return false;
- size_t startOffset = address;
- uint32_t fileSize = 0;
- if (!AppendFile(rom, fileName, &address, &fileSize)) return false;
- table[ovNum].compressedSize = fileSize;
- table[ovNum].isCompressed = true;
- uint32_t fileId = data[ovNum].fileId;
- if (fileId >= MAX_OVERLAYS) FATAL("Overlay %ld's file ID (%d) exceeds the maximum %d\n", ovNum, fileId, MAX_OVERLAYS);
- fatEntries[fileId].startOffset = startOffset;
- fatEntries[fileId].endOffset = address;
- }
-
- if (!ChangeDir("..")) return false;
-
- *pAddress = address;
- return true;
-}
-
-bool RewriteArm9OverlayTable(File *rom, const Header *header, OverlayEntry *entries, size_t numEntries) {
- size_t prevAddress = FileOffset(rom);
- FileGoTo(rom, header->arm9Overlays.offset);
- if (!FileWrite(rom, entries, sizeof(*entries), numEntries)) FATAL("Failed to rewrite ARM9 overlay table\n");
- FileGoTo(rom, prevAddress);
- return true;
-}
-
-bool WriteArm9Overlays(
- File *rom,
- size_t *pAddress,
- Header *pHeader,
- const char *overlayDataFile,
- FatEntry *fatEntries,
- size_t *pNumOverlays
-) {
- size_t address = *pAddress;
-
- OverlayEntry *entries;
- OverlayData *data;
- size_t numOverlays;
- if (!WriteArm9OverlayTable(rom, &address, pHeader, overlayDataFile, &entries, &data, &numOverlays)) return false;
- if (!WriteArm9OverlayFiles(rom, &address, numOverlays, fatEntries, entries, data)) return false;
- if (!RewriteArm9OverlayTable(rom, pHeader, entries, numOverlays)) return false;
-
- free(data);
- free(entries);
-
- *pAddress = address;
- *pNumOverlays = numOverlays;
- return true;
-}
-
-typedef struct {
- FntEntry *table;
- uint16_t tableSize;
- uint16_t tableMax;
-
- uint16_t nextFileId;
- uint16_t parentId;
-
- uint8_t *subtable;
- size_t subtableSize;
- size_t subtableMax;
-} FntContext;
-
-bool GrowFntTable(FntContext *pContext, size_t minEntries) {
- FntContext ctx;
- memcpy(&ctx, pContext, sizeof(ctx));
-
- if (minEntries <= ctx.tableMax) return true;
- while (minEntries > ctx.tableMax) {
- ctx.tableMax *= 2;
- }
-
- FntEntry *newTable = realloc(ctx.table, ctx.tableMax * sizeof(FntEntry));
- if (newTable == NULL) FATAL("Failed to reallocate FNT table to %d entries\n", ctx.tableMax);
- ctx.table = newTable;
-
- memcpy(pContext, &ctx, sizeof(ctx));
- return true;
-}
-
-bool GrowFntSubtable(FntContext *pContext, size_t growSize) {
- FntContext ctx;
- memcpy(&ctx, pContext, sizeof(ctx));
-
- if (ctx.subtableSize + growSize < ctx.subtableMax) return true;
- while (ctx.subtableSize + growSize >= ctx.subtableMax) {
- ctx.subtableMax *= 2;
- }
-
- uint8_t *newTable = realloc(ctx.subtable, ctx.subtableMax);
- if (newTable == NULL) FATAL("Failed to reallocate FNT subtable to %ld bytes\n", ctx.subtableMax);
- ctx.subtable = newTable;
-
- memcpy(pContext, &ctx, sizeof(ctx));
- return true;
-}
-
-bool WriteFntSubtable(FileTree *tree, FntContext *pContext) {
- FntContext ctx;
- memcpy(&ctx, pContext, sizeof(ctx));
- size_t subtableStart = ctx.subtableSize;
-
- // Create initial subtable entries
- uint16_t fileId = ctx.nextFileId;
- for (size_t i = 0; i < tree->numChildren; ++i) {
- FileTree *child = &tree->children[i];
- FntSubEntry *entry = child->entry;
- if (!entry->isSubdir) {
- child->firstFileId = fileId;
- fileId += 1;
- }
-
- size_t entrySize = sizeof(*entry) + entry->length + (entry->isSubdir ? 2 : 0);
- if (!GrowFntSubtable(&ctx, entrySize)) return false;
-
- FntSubEntry *dest = (FntSubEntry*) (ctx.subtable + ctx.subtableSize);
- memcpy(dest, entry, entrySize);
- ctx.subtableSize += entrySize;
- }
-
- if (!GrowFntSubtable(&ctx, 1)) return false;
- ctx.subtable[ctx.subtableSize] = 0; // End of subtable
- ctx.subtableSize += 1;
-
- ctx.nextFileId = fileId;
-
- // Recurse child directories
- for (size_t i = 0; i < tree->numChildren; ++i) {
- FileTree *child = &tree->children[i];
- FntSubEntry *entry = child->entry;
- if (!entry->isSubdir) continue;
- uint16_t subdirId = 0xf000 | ctx.tableSize;
- WRITE_SUBDIR_ID(entry, subdirId);
- child->firstFileId = ctx.nextFileId;
- FntEntry mainEntry;
- mainEntry.subtableOffset = ctx.subtableSize; // will add main table length later
- mainEntry.firstFile = ctx.nextFileId;
- mainEntry.parentId = ctx.parentId;
- if (!GrowFntTable(&ctx, ctx.tableSize + 1)) return false;
- memcpy(&ctx.table[ctx.tableSize], &mainEntry, sizeof(mainEntry));
- ctx.tableSize += 1;
-
- uint16_t oldParentId = ctx.parentId;
- ctx.parentId = subdirId;
-
- char name[128];
- strncpy(name, entry->name, entry->length);
- name[entry->length] = '\0';
- if (!WriteFntSubtable(child, &ctx)) return false;
-
- ctx.parentId = oldParentId;
- }
-
- // Update subdir IDs
- size_t subtableOffset = 0;
- for (size_t i = 0; i < tree->numChildren; ++i) {
- FileTree *child = &tree->children[i];
- FntSubEntry *entry = child->entry;
- size_t entrySize = sizeof(*entry) + entry->length + (entry->isSubdir ? 2 : 0);
- memcpy(ctx.subtable + subtableStart + subtableOffset, entry, entrySize);
- subtableOffset += entrySize;
- }
-
- memcpy(pContext, &ctx, sizeof(ctx));
- return true;
-}
-
-bool WriteFnt(File *rom, size_t *pAddress, FileTree *pRoot, size_t firstFileId, size_t *pNumFiles) {
- size_t address = *pAddress;
-
- FntContext ctx;
- ctx.table = malloc(INITIAL_TABLE_SIZE * sizeof(FntEntry));
- if (ctx.table == NULL) FATAL("Failed to allocate FNT table\n");
- ctx.tableSize = 1;
- ctx.tableMax = INITIAL_TABLE_SIZE;
-
- ctx.nextFileId = firstFileId;
- ctx.parentId = 0xf000; // root directory
-
- ctx.subtable = malloc(INITIAL_SUBTABLE_SIZE);
- if (ctx.subtable == NULL) FATAL("Failed to allocate FNT subtable\n");
- ctx.subtableSize = 0;
- ctx.subtableMax = INITIAL_SUBTABLE_SIZE;
-
- ctx.table[0].subtableOffset = 0; // will add main table length later
- ctx.table[0].firstFile = firstFileId;
- ctx.table[0].parentId = 0; // will be set to number of directories later
-
- if (!WriteFntSubtable(pRoot, &ctx)) return false;
- ctx.table[0].parentId = ctx.tableSize;
-
- size_t tableLength = ctx.tableSize * sizeof(FntEntry);
- for (size_t i = 0; i < ctx.tableSize; ++i) {
- ctx.table[i].subtableOffset += tableLength;
- }
- if (!FileWrite(rom, ctx.table, sizeof(FntEntry), ctx.tableSize)) FATAL("Failed to write FNT table\n");
- address += ctx.tableSize * sizeof(FntEntry);
- if (!FileWrite(rom, ctx.subtable, ctx.subtableSize, 1)) FATAL("Failed to write FNT subtables\n");
- address += ctx.subtableSize;
-
- free(ctx.table);
- free(ctx.subtable);
-
- *pAddress = address;
- *pNumFiles = ctx.nextFileId;
- return true;
-}
-
-bool WriteFat(File *rom, size_t *pAddress, size_t numFiles) {
- size_t address = *pAddress;
-
- FatEntry blank;
- blank.startOffset = 0;
- blank.endOffset = 0;
- for (size_t i = 0; i < numFiles; ++i) {
- if (!FileWrite(rom, &blank, sizeof(blank), 1)) FATAL("Failed to write blank placeholder FAT entry\n");
- }
- address += sizeof(blank) * numFiles;
-
- *pAddress = address;
- return true;
-}
-
-bool ReadTitle(const char *language, const char *titleFile, wchar_t *title, size_t titleSize) {
- char buf[1024];
- memset(buf, 0, sizeof(buf));
- File file;
- if (!FileOpenRead(titleFile, &file)) FATAL("Failed to open %s banner title '%s'\n", language, titleFile);
-
- size_t fileSize = FileSize(&file);
- if (fileSize > sizeof(buf) - 1) FATAL("Buffer too small for %s banner title '%s'\n", language, titleFile);
-
- if (FileRead(&file, buf, fileSize, 1) != 1) FATAL("Failed to read %s banner title '%s'\n", language, titleFile);
- FileClose(&file);
-
- memset(title, 0, titleSize);
- if (!Utf8ToWchar(buf, fileSize, title, titleSize)) return false;
- return true;
-}
-
-bool WriteBanner(File *rom, size_t *pAddress) {
- size_t address = *pAddress;
-
- File file;
-
- Banner banner;
- banner.version = 1;
- memset(banner.reserved0, 0, sizeof(banner.reserved0));
-
- if (!FileOpenRead(ICON_BITMAP_FILE, &file)) FATAL("Failed to open banner icon bitmap '" ICON_BITMAP_FILE "'\n");
- if (FileRead(&file, banner.iconBitmap, sizeof(banner.iconBitmap), 1) != 1) {
- FATAL("Failed to read banner icon bitmap '" ICON_BITMAP_FILE "'\n");
- }
- FileClose(&file);
-
- if (!FileOpenRead(ICON_PALETTE_FILE, &file)) FATAL("Failed to open banner icon palette '" ICON_PALETTE_FILE "'\n");
- if (FileRead(&file, banner.iconPalette, sizeof(banner.iconPalette), 1) != 1) {
- FATAL("Failed to read banner icon palette '" ICON_PALETTE_FILE "'\n");
- }
- FileClose(&file);
-
- if (!ReadTitle("Japanese", TITLE_JAP_FILE, banner.japaneseTitle, sizeof(banner.japaneseTitle))) return false;
- if (!ReadTitle("English", TITLE_ENG_FILE, banner.englishTitle, sizeof(banner.englishTitle))) return false;
- if (!ReadTitle("French", TITLE_FRE_FILE, banner.frenchTitle, sizeof(banner.frenchTitle))) return false;
- if (!ReadTitle("German", TITLE_GER_FILE, banner.germanTitle, sizeof(banner.germanTitle))) return false;
- if (!ReadTitle("Italian", TITLE_ITA_FILE, banner.italianTitle, sizeof(banner.italianTitle))) return false;
- if (!ReadTitle("Spanish", TITLE_SPA_FILE, banner.spanishTitle, sizeof(banner.spanishTitle))) return false;
-
- uint8_t *crcStart = (uint8_t*) &banner + offsetof(Banner, iconBitmap);
- uint8_t *crcEnd = (uint8_t*) &banner + sizeof(banner);
- banner.crc = Crc(crcStart, crcEnd - crcStart);
-
- if (!FileWrite(rom, &banner, sizeof(banner), 1)) FATAL("Failed to write banner\n");
- address += sizeof(banner);
-
- *pAddress = address;
- return true;
-}
-
-bool TraverseAndAppendAssets(File *rom, size_t *pAddress, const FileTree *tree, FatEntry *entries, uint16_t firstFileId) {
- size_t address = *pAddress;
-
- for (size_t i = 0; i < tree->numChildren; ++i) {
- FileTree *child = &tree->children[i];
- if (child->addedToFat) continue;
- FntSubEntry *entry = child->entry;
- char name[128];
- strncpy(name, entry->name, entry->length);
- name[entry->length] = '\0';
- if (!entry->isSubdir) {
- if (!Align(512, rom, &address)) return false;
- size_t startOffset = address;
- if (!AppendFile(rom, name, &address, NULL)) return false;
- // For files, `firstFileId` is the ID of the file
- entries[child->firstFileId].startOffset = startOffset;
- entries[child->firstFileId].endOffset = address;
- continue;
- }
- if (!ChangeDir(name)) return false;
- if (!TraverseAndAppendAssets(rom, &address, child, entries, child->firstFileId)) return false;
- if (!ChangeDir("..")) return false;
- }
-
- *pAddress = address;
- return true;
-}
-
-bool AppendAssets(
- File *rom,
- size_t *pAddress,
- FileTree *root,
- FatEntry *entries,
- size_t numOverlays,
- const char *assetsListFile
-) {
- size_t address = *pAddress;
-
- if (assetsListFile == NULL) {
- if (!TraverseAndAppendAssets(rom, &address, root, entries, numOverlays)) return false;
- *pAddress = address;
- return true;
- }
-
- File file;
- if (!FileOpenRead(assetsListFile, &file)) FATAL("Failed to open assets list file '%s'\n", assetsListFile);
- size_t listSize = FileSize(&file);
- char *assetsList = malloc(listSize + 1);
- if (assetsList == NULL) FATAL("Failed to allocate string for assets list file '%s'\n", assetsListFile);
- if (FileRead(&file, assetsList, listSize, 1) != 1) FATAL("Failed to read from assets list file '%s'\n", assetsListFile);
- FileClose(&file);
- assetsList[listSize] = '\0';
-
- char assetsDir[256];
- if (!GetCurrentDir(assetsDir, sizeof(assetsDir))) FATAL("Failed to get assets directory\n");
-
- char *const listEnd = assetsList + listSize;
- for (char *path = assetsList, *next; path < listEnd; path = next) {
- next = SplitLine(path);
- if (*path != '/') continue;
- FileTree *subTree = FindSubTree(root, path);
- if (subTree == NULL) continue;
-
- // First file ID of root directory is given from number of overlays
- uint16_t firstFileId = subTree->entry == NULL ? numOverlays : subTree->firstFileId;
-
- if (path[1] != '\0' && !ChangeDir(&path[1])) return false;
- if (!TraverseAndAppendAssets(rom, &address, subTree, entries, firstFileId)) return false;
- if (!ChangeDir(assetsDir)) return false;
-
- subTree->addedToFat = true;
- }
-
- free(assetsList);
-
- *pAddress = address;
- return true;
-}
-
-bool RewriteFat(File *rom, size_t fatStart, const FatEntry *entries, size_t numFiles) {
- size_t prevPos = FileOffset(rom);
- FileGoTo(rom, fatStart);
- if (!FileWrite(rom, entries, sizeof(*entries), numFiles)) FATAL("Failed to rewrite FAT table\n");
- FileGoTo(rom, prevPos);
- return true;
-}
-
-bool FinalizeHeader(File *rom, Header *pHeader, const char *arm7bios, uint32_t *secureArea, const Arm9Metadata *metadata) {
- Header header;
- memcpy(&header, pHeader, sizeof(header));
-
- if (arm7bios != NULL) {
- File file;
- if (!FileOpenRead(arm7bios, &file)) FATAL("Failed to open ARM7 BIOS '%s'\n", arm7bios);
- FileGoTo(&file, 0x30);
- uint8_t encKey[sizeof(Blowfish)];
- if (FileRead(&file, &encKey, sizeof(encKey), 1) != 1) FATAL("Failed to read encrypion key\n");
- FileClose(&file);
-
- if (!BlowfishInit(encKey, pHeader, 3)) return false;
- for (size_t i = 2; i < 0x200; i += 2) {
- BlowfishEncrypt(&secureArea[i], &secureArea[i + 1]);
- }
- memcpy(secureArea, "encryObj", 8);
- BlowfishEncrypt(&secureArea[0], &secureArea[1]);
- if (!BlowfishInit(encKey, pHeader, 2)) return false;
- BlowfishEncrypt(&secureArea[0], &secureArea[1]);
- header.secureAreaCrc = Crc(secureArea, SECURE_AREA_SIZE);
- }
-
- header.arm9.entry = metadata->entryAddr;
- header.arm9.baseAddr = metadata->baseAddr;
- header.arm9AutoloadCallback = metadata->autoloadCallback;
- header.autoloadBlockInfosOffset = header.arm9.offset + metadata->autoloadBlockInfos;
-
- header.headerCrc = Crc(&header, offsetof(Header, headerCrc));
-
- size_t prevPos = FileOffset(rom);
- FileGoTo(rom, 0);
- if (!FileWrite(rom, &header, sizeof(header), 1)) {
- fprintf(stderr, "Failed to rewrite header\n");
- return 1;
- }
- FileGoTo(rom, prevPos);
-
- memcpy(pHeader, &header, sizeof(header));
- return true;
-}
-
-void PrintUsage(const char *program) {
- printf(
- "buildrom " VERSION "\n"
- "\n"
- "Usage: %s -a BASEDIR -b BUILDDIR -r REGION -o OUTFILE [-7 ARM7BIOS] [-s ASSETS]\n"
- " -a BASEDIR \tBase directory generated by extractrom\n"
- " -b BUILDDIR\tBuild directory generated by Makefile\n"
- " -r REGION \tJ = Japan, E = USA, P = Europe\n"
- " -o OUTFILE \tOutput ROM file\n"
- " -7 ARM7BIOS\tPath to ARM7 BIOS file\n"
- " -s ASSETS \tPath to assets list\n",
- program
- );
-}
-
-int main(int argc, char **argv) {
-
- // --------------------- Parse command line arguments ---------------------
- const char *program = argv[0];
- if (argc == 1) {
- PrintUsage(program);
- return 0;
- }
- const char *baseDir = NULL;
- const char *buildDir = NULL;
- const char *romFile = NULL;
- const char *arm7biosFile = NULL;
- char *assetsListFile = NULL;
- Region region = 0;
- for (int i = 1; i < argc; ++i) {
- if (strcmp(argv[i], "-o") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected filename after -o\n");
- return 1;
- }
- romFile = argv[i];
- } else if (strcmp(argv[i], "-a") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected pathname after -a\n");
- return 1;
- }
- baseDir = argv[i];
- } else if (strcmp(argv[i], "-b") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected pathname after -b\n");
- return 1;
- }
- buildDir = argv[i];
- } else if (strcmp(argv[i], "-7") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected pathname after -7\n");
- return 1;
- }
- arm7biosFile = argv[i];
- } else if (strcmp(argv[i], "-s") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected pathname after -s\n");
- return 1;
- }
- assetsListFile = argv[i];
- } else if (strcmp(argv[i], "-r") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected region after -r\n");
- return 1;
- }
- if (strlen(argv[i]) != 1) {
- fprintf(stderr, "Region must be a single character\n");
- return 1;
- }
- region = argv[i][0];
- } else {
- fprintf(stderr, "Unknown option '%s'\n", argv[i]);
- return 1;
- }
- }
- if (baseDir == NULL) {
- PrintUsage(program);
- fprintf(stderr, "Please provide a base directory, see usage above\n");
- return 1;
- }
- if (buildDir == NULL) {
- PrintUsage(program);
- fprintf(stderr, "Please provide a build directory, see usage above\n");
- return 1;
- }
- if (region != REGION_JAPAN && region != REGION_USA && region != REGION_EUROPE) {
- PrintUsage(program);
- fprintf(stderr, "Invalid region '%c', see usage above\n", region);
- return 1;
- }
- if (romFile == NULL) {
- PrintUsage(program);
- fprintf(stderr, "Please provide an output ROM file, see usage above\n");
- return 1;
- }
-
-
- // --------------------- Set up ---------------------
- char rootDir[256];
- if (!GetCurrentDir(rootDir, sizeof(rootDir))) {
- fprintf(stderr, "Failed to get root directory\n");
- return 1;
- }
-
- File rom;
- if (!FileOpenWrite(romFile, &rom)) {
- fprintf(stderr, "Failed to open output ROM file '%s'\n", romFile);
- return 1;
- }
-
- readBuffer = malloc(BUFFER_SIZE);
- if (readBuffer == NULL) {
- fprintf(stderr, "Failed to allocate read buffer to %d bytes\n", BUFFER_SIZE);
- return 1;
- }
-
- GenerateCrcTable();
-
-
- // --------------------- Write initial header ---------------------
- BuildInfo info;
- info.region = region;
- size_t address = 0;
-
- Header header;
- InitHeader(&header, &info);
-
- if (!FileWrite(&rom, &header, sizeof(header), 1)) {
- fprintf(stderr, "Failed to write NDS header\n");
- return 1;
- }
- address += sizeof(header);
-
-
- // --------------------- Get canonical file paths ---------------------
- if (assetsListFile != NULL && !AllocFullPath(assetsListFile, &assetsListFile)) return 1;
- if (!ChangeDir(baseDir)) return 1;
- char *arm9overlayDataFile = NULL;
- if (!AllocFullPath(ARM9_OVERLAY_DATA_FILE, &arm9overlayDataFile)) return 1;
- if (!ChangeDir(rootDir)) return 1;
-
-
- // --------------------- Write ARM9 program ---------------------
- if (!ChangeDir(buildDir)) return 1;
-
- if (!Align(512, &rom, &address)) return 1;
- header.arm9.offset = address;
-
- Arm9Metadata metadata;
- if (!LoadArm9Metadata(&metadata)) return 1;
- uint32_t secureArea[SECURE_AREA_SIZE / sizeof(uint32_t)];
- if (!WriteArm9Program(&rom, &address, &header.arm9.size, secureArea, &metadata)) return 1;
- if (!AppendFile(&rom, ARM9_FOOTER_FILE, &address, NULL)) return 1;
-
-
- // --------------------- Write ARM9 overlay table and overlay files ---------------------
- if (!Align(512, &rom, &address)) return 1;
- header.arm9Overlays.offset = address;
- size_t numOverlays = 0;
- FatEntry overlayEntries[MAX_OVERLAYS];
- if (!WriteArm9Overlays(&rom, &address, &header, arm9overlayDataFile, overlayEntries, &numOverlays)) return 1;
- FreeFullPath(&arm9overlayDataFile);
-
- if (!ChangeDir(rootDir)) return 1;
-
- if (!ChangeDir(baseDir)) return 1;
-
-
- // --------------------- Write ARM7 program ---------------------
- if (!Align(512, &rom, &address)) return 1;
- header.arm7.offset = address;
- if (!AppendFile(&rom, ARM7_PROGRAM_FILE, &address, &header.arm7.size)) return 1;
-
- if (!ChangeDir(ASSETS_SUBDIR)) return 1;
-
-
- // --------------------- Write file name table (FNT) ---------------------
- FileTree root;
- if (!MakeFileTree(&root)) return false;
- if (!SortFileTree(&root, CompareFileTreeNormal)) return false;
-
- if (!Align(512, &rom, &address)) return 1;
- size_t numFiles = 0;
- header.fileNames.offset = address;
- if (!WriteFnt(&rom, &address, &root, numOverlays, &numFiles)) return 1;
- header.fileNames.size = address - header.fileNames.offset;
-
-
- // --------------------- Write file allocation table (FAT) ---------------------
- if (!Align(512, &rom, &address)) return 1;
- header.fileAllocs.offset = address;
- if (!WriteFat(&rom, &address, numFiles)) return 1;
- header.fileAllocs.size = address - header.fileAllocs.offset;
- FatEntry *fatEntries = malloc(numFiles * sizeof(FatEntry));
- memcpy(fatEntries, overlayEntries, numOverlays * sizeof(*fatEntries));
-
- if (!ChangeDir("..")) return 1;
-
-
- // --------------------- Write banner ---------------------
- if (!Align(512, &rom, &address)) return false;
- header.bannerOffset = address;
- if (!WriteBanner(&rom, &address)) return false;
-
- if (!ChangeDir(ASSETS_SUBDIR)) return 1;
-
-
- // --------------------- Write assets ---------------------
- if (!Align(512, &rom, &address)) return false;
- if (!SortFileTree(&root, CompareFileTreeAscii)) return false;
- if (!AppendAssets(&rom, &address, &root, fatEntries, numOverlays, assetsListFile)) return false;
- if (assetsListFile != NULL) FreeFullPath(&assetsListFile);
-
- if (!RewriteFat(&rom, header.fileAllocs.offset, fatEntries, numFiles))
- free(fatEntries);
-
- if (!FreeFileTree(&root)) return false;
-
- if (!ChangeDir("..")) return 1;
-
- if (!ChangeDir(rootDir)) return 1;
-
-
- // --------------------- Write padding ---------------------
- header.romSize = address;
- header.capacity = 15 - __builtin_clz(header.romSize);
- size_t romEnd = 1 << (17 + header.capacity);
- if (!Align(romEnd, &rom, &address)) return 1;
-
-
- // --------------------- Update header ---------------------
- char *arm7bios = NULL;
- if (arm7biosFile != NULL && !AllocFullPath(arm7biosFile, &arm7bios)) return 1;
-
- if (!ChangeDir(buildDir)) return 1;
-
- if (!FinalizeHeader(&rom, &header, arm7bios, secureArea, &metadata)) return false;
- FreeFullPath(&arm7bios);
-
- if (!ChangeDir(rootDir)) return 1;
-
- free(readBuffer);
- FileClose(&rom);
-}
diff --git a/tools/rom/extract.c b/tools/rom/extract.c
deleted file mode 100644
index b677b76c..00000000
--- a/tools/rom/extract.c
+++ /dev/null
@@ -1,395 +0,0 @@
-#include <stdbool.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "rom.h"
-#include "ph.h"
-#include "util.h"
-
-#define VERSION "1.0.2"
-#define INDENT 4
-
-// Command line flags for debugging purposes
-bool printFileHierarchy = false;
-bool printFileAllocOrder = false;
-
-void Indent(size_t depth) {
- char spaces[INDENT + 1];
- memset(spaces, ' ', INDENT);
- spaces[INDENT] = '\0';
- for (size_t i = 0; i < depth; ++i) {
- puts(spaces);
- }
-}
-
-bool CheckRegion(const Header *pHeader, BuildInfo *pInfo) {
- Region region = pHeader->gamecode[3];
- if (
- memcmp(pHeader->gamecode, GAMECODE_PREFIX, 3) != 0 || (
- region != REGION_JAPAN &&
- region != REGION_USA &&
- region != REGION_EUROPE
- )
- ) {
- FATAL("Invalid gamecode prefix '%.4s'\n", pHeader->gamecode);
- }
-
- pInfo->region = region;
- return true;
-}
-
-bool ExtractArm7(const uint8_t *rom, ProgramOffset *pArm7) {
- File file;
- if (!FileOpenWrite(ARM7_PROGRAM_FILE, &file)) FATAL("Failed to create ARM7 program '" ARM7_PROGRAM_FILE "'\n");
- if (!FileWrite(&file, rom + pArm7->offset, pArm7->size, 1)) FATAL("Failed to write ARM7 program '" ARM7_PROGRAM_FILE "'\n");
- FileClose(&file);
- return true;
-}
-
-bool ExtractTitle(const char *language, const char *fileName, const wchar_t *title, size_t titleSize) {
- char buf[1024];
- File file;
- if (!FileOpenWrite(fileName, &file)) FATAL("Failed to create %s banner title '%s'\n", language, fileName);
-
- size_t resultSize = 0;
- if (!WcharToUtf8((wchar_t*) title, titleSize, buf, sizeof(buf), &resultSize)) return false;
- size_t len = strlen(buf);
- if (!FileWrite(&file, buf, len, 1)) FATAL("Failed to write %s banner title '%s'\n", language, fileName);
- FileClose(&file);
- return true;
-}
-
-bool ExtractBanner(const Banner *pBanner, const BuildInfo *pInfo) {
- if (!MakeDir(BANNER_SUBDIR)) return 1;
-
- File file;
-
- if (!FileOpenWrite(ICON_BITMAP_FILE, &file)) FATAL("Failed to create banner icon bitmap '" ICON_BITMAP_FILE "'\n");
- if (!FileWrite(&file, pBanner->iconBitmap, sizeof(pBanner->iconBitmap), 1)) {
- FATAL("Failed to write banner icon bitmap '" ICON_BITMAP_FILE "'\n");
- }
- FileClose(&file);
-
- if (!FileOpenWrite(ICON_PALETTE_FILE, &file)) FATAL("Failed to create banner icon palette '" ICON_PALETTE_FILE "'\n");
- if (!FileWrite(&file, pBanner->iconPalette, sizeof(pBanner->iconPalette), 1)) {
- FATAL("Failed to write banner icon palette '" ICON_PALETTE_FILE "'\n");
- }
- FileClose(&file);
-
- if (!ExtractTitle("Japanese", TITLE_JAP_FILE, pBanner->japaneseTitle, sizeof(pBanner->japaneseTitle))) return false;
- if (!ExtractTitle("English", TITLE_ENG_FILE, pBanner->englishTitle, sizeof(pBanner->englishTitle))) return false;
- if (!ExtractTitle("French", TITLE_FRE_FILE, pBanner->frenchTitle, sizeof(pBanner->frenchTitle))) return false;
- if (!ExtractTitle("German", TITLE_GER_FILE, pBanner->germanTitle, sizeof(pBanner->germanTitle))) return false;
- if (!ExtractTitle("Italian", TITLE_ITA_FILE, pBanner->italianTitle, sizeof(pBanner->italianTitle))) return false;
- if (!ExtractTitle("Spanish", TITLE_SPA_FILE, pBanner->spanishTitle, sizeof(pBanner->spanishTitle))) return false;
-
- return true;
-}
-
-typedef struct {
- char basePath[256];
- size_t basePathLen;
- char **filePathList;
- size_t numFilePaths;
- size_t maxFilePaths;
-
- size_t depth;
-} ExtractContext;
-
-bool GrowFilePathList(ExtractContext *pContext, size_t minEntries) {
- ExtractContext ctx;
- memcpy(&ctx, pContext, sizeof(ctx));
-
- if (minEntries <= ctx.maxFilePaths) return true;
- while (minEntries > ctx.maxFilePaths) {
- ctx.maxFilePaths *= 2;
- }
-
- char **newFilePathList = realloc(ctx.filePathList, ctx.maxFilePaths * sizeof(*ctx.filePathList));
- if (newFilePathList == NULL) FATAL("Failed to reallocate file path list to %ld entries\n", ctx.maxFilePaths);
- ctx.filePathList = newFilePathList;
-
- // Fill new entries with 0
- memset(&ctx.filePathList[pContext->maxFilePaths], 0, (ctx.maxFilePaths - pContext->maxFilePaths) * sizeof(*ctx.filePathList));
-
- memcpy(pContext, &ctx, sizeof(ctx));
- return true;
-}
-
-bool ExtractSubtable(
- const uint8_t *rom,
- const uint8_t *fatStart,
- const uint8_t *fntStart,
- const FntEntry *pFntEntry,
- ExtractContext *pContext
-) {
- ExtractContext ctx;
- memcpy(&ctx, pContext, sizeof(ctx));
-
- const uint8_t *subEntryAddr = fntStart + pFntEntry->subtableOffset;
- const FntSubEntry *pSubEntry = (const FntSubEntry*) subEntryAddr;
- uint16_t fileId = pFntEntry->firstFile;
- while(pSubEntry->length > 0) {
- char name[128];
- memcpy(name, pSubEntry->name, pSubEntry->length);
- name[pSubEntry->length] = '\0';
-
- if (!pSubEntry->isSubdir) {
- if (printFileHierarchy) {
- Indent(ctx.depth);
- printf("%d: %s\n", fileId, name);
- }
-
- const FatEntry *pFatEntry = (const FatEntry*) fatStart + fileId;
- size_t fileSize = pFatEntry->endOffset - pFatEntry->startOffset;
- const uint8_t *pFileBytes = rom + pFatEntry->startOffset;
-
- File file;
- if (!FileOpenWrite(name, &file)) FATAL("Failed to open assets file '%s'\n", name);
- if (!FileWrite(&file, pFileBytes, fileSize, 1)) FATAL("Failed to write to assets file '%s'\n", name);
- FileClose(&file);
-
- if (printFileAllocOrder) {
- if (!GrowFilePathList(&ctx, fileId + 1)) return false;
- char *filePath = malloc(ctx.basePathLen + pSubEntry->length + 1);
- if (filePath == NULL) FATAL("Failed to allocate string for file path\n");
- sprintf(filePath, "%s%s", ctx.basePath, name);
- ctx.filePathList[fileId] = filePath;
- }
-
- subEntryAddr += sizeof(FntSubEntry) + pSubEntry->length;
- pSubEntry = (const FntSubEntry*) subEntryAddr;
- ++fileId;
- continue;
- }
-
- if (printFileHierarchy) {
- Indent(ctx.depth);
- printf("%s {\n", name);
- }
- if (!MakeDir(name)) return false;
- if (!ChangeDir(name)) return false;
-
- uint16_t subdirId = READ_SUBDIR_ID(pSubEntry);
- uint16_t subdirIndex = subdirId & 0xfff;
- ctx.depth += 1;
-
- if (printFileAllocOrder) {
- size_t basePathSpace = sizeof(ctx.basePath) - ctx.basePathLen;
- size_t basePathAdded = snprintf(&ctx.basePath[ctx.basePathLen], basePathSpace, "%s/", name);
- if (basePathAdded >= basePathSpace) FATAL("Maximum base path size was exceeded\n");
- ctx.basePathLen += basePathAdded;
- if (!ExtractSubtable(rom, fatStart, fntStart, (FntEntry*) fntStart + subdirIndex, &ctx)) return false;
- ctx.basePathLen -= basePathAdded;
- memset(&ctx.basePath[ctx.basePathLen], 0, basePathAdded);
- } else {
- if (!ExtractSubtable(rom, fatStart, fntStart, (FntEntry*) fntStart + subdirIndex, &ctx)) return false;
- }
- ctx.depth -= 1;
-
- if (printFileHierarchy) {
- Indent(ctx.depth);
- printf("}\n");
- }
-
- if (!ChangeDir("..")) return false;
- subEntryAddr += sizeof(FntSubEntry) + pSubEntry->length + sizeof(subdirId);
- pSubEntry = (const FntSubEntry*) subEntryAddr;
- }
-
- memcpy(pContext, &ctx, sizeof(ctx));
- return true;
-}
-
-typedef struct {
- uint32_t fileId;
- uint32_t startOffset;
- uint32_t endOffset;
-} FatInfo;
-
-int32_t CompareFatInfo(const void *a, const void *b) {
- const FatInfo *infoA = (FatInfo*) a;
- const FatInfo *infoB = (FatInfo*) b;
- return infoA->startOffset - infoB->startOffset;
-}
-
-bool PrintFileAllocOrder(ExtractContext *ctx, const uint8_t *fatAddr) {
- const FatEntry *fatStart = (FatEntry*) fatAddr;
- const FatEntry *fat;
- for (fat = fatStart; fat->startOffset != 0xFFFFFFFF; ++fat);
- size_t numFiles = fat - fatStart;
-
- FatInfo *fatInfo = malloc(numFiles * sizeof(FatInfo));
- if (fatInfo == NULL) FATAL("Failed to allocate array for printing file allocation order\n");
- for (size_t i = 0; i < numFiles; ++i) {
- fatInfo[i].fileId = i;
- fatInfo[i].startOffset = fatStart[i].startOffset;
- fatInfo[i].endOffset = fatStart[i].endOffset;
- }
-
- qsort(fatInfo, numFiles, sizeof(*fatInfo), CompareFatInfo);
-
- for (size_t i = 0; i < numFiles; ++i) {
- uint32_t fileId = fatInfo[i].fileId;
- if (ctx->filePathList[fileId] == NULL) continue;
- printf("%s\n", ctx->filePathList[fileId]);
- }
-
- free(fatInfo);
- return true;
-}
-
-bool ExtractAssets(const uint8_t *rom, const uint8_t *fatStart, const uint8_t *fntStart) {
- ExtractContext ctx;
- memset(ctx.basePath, 0, sizeof(ctx.basePath));
- ctx.basePathLen = 0;
- ctx.numFilePaths = 0;
- if (printFileAllocOrder) {
- ctx.maxFilePaths = 4096;
- ctx.filePathList = calloc(ctx.maxFilePaths, sizeof(*ctx.filePathList));
- } else {
- ctx.maxFilePaths = 0;
- ctx.filePathList = NULL;
- }
- ctx.depth = 0;
-
- if (!ExtractSubtable(rom, fatStart, fntStart, (FntEntry*) fntStart, &ctx)) return false;
- if (printFileAllocOrder) {
- if (!PrintFileAllocOrder(&ctx, fatStart)) return false;
- for (size_t i = 0; i < ctx.numFilePaths; ++i) {
- if (ctx.filePathList[i] != NULL) free(ctx.filePathList[i]);
- }
- free(ctx.filePathList);
- }
- return true;
-}
-
-bool ExtractOverlayData(const uint8_t *rom, const Header *header) {
- const OverlayEntry *entry = (OverlayEntry*) (rom + header->arm9Overlays.offset);
- const OverlayEntry *end = entry + header->arm9Overlays.size / sizeof(OverlayEntry);
-
- File file;
- if (!FileOpenWrite(ARM9_OVERLAY_DATA_FILE, &file)) {
- FATAL("Failed to open overlay data file '" ARM9_OVERLAY_DATA_FILE "'\n");
- }
- for(; entry < end; ++entry) {
- OverlayData data;
- data.fileId = entry->fileId;
- if (!FileWrite(&file, &data, sizeof(data), 1)) FATAL("Failed to write overlay data to '" ARM9_OVERLAY_DATA_FILE "'\n");
- }
-
- FileClose(&file);
- return true;
-}
-
-void PrintUsage(const char *program) {
- printf(
- "extractrom " VERSION "\n"
- "\n"
- "Usage: %s -i ROMFILE -o OUTDIR [-n] [-a] [-l]\n"
- " -o OUTDIR \tDirectory to extract files to\n"
- " -i ROMFILE\tROM to extract from\n"
- " -n \tPrints file name hierarchy to stdout\n"
- " -a \tPrints file allocation order to stdout\n",
- program
- );
-}
-
-int main(int argc, const char **argv) {
-
- // --------------------- Parse command line arguments ---------------------
- const char *program = argv[0];
- if (argc == 1) {
- PrintUsage(program);
- return 0;
- }
- const char *romFile = NULL;
- const char *outDir = NULL;
- for (int i = 1; i < argc; ++i) {
- if (strcmp(argv[i], "-o") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected dirname after -o\n");
- return 1;
- }
- outDir = argv[i];
- } else if (strcmp(argv[i], "-i") == 0) {
- if (++i >= argc) {
- fprintf(stderr, "Expected filename after -i\n");
- return 1;
- }
- romFile = argv[i];
- } else if (strcmp(argv[i], "-n") == 0) {
- printFileHierarchy = true;
- } else if (strcmp(argv[i], "-a") == 0) {
- printFileAllocOrder = true;
- } else {
- fprintf(stderr, "Unknown option '%s'\n", argv[i]);
- return 1;
- }
- }
- if (romFile == NULL) {
- PrintUsage(program);
- fprintf(stderr, "Please provide a ROM file, see usage above.\n");
- return 1;
- }
- if (outDir == NULL) {
- PrintUsage(program);
- fprintf(stderr, "Please provide an output directory, see usage above.\n");
- return 1;
- }
-
-
- // --------------------- Load ROM ---------------------
- File fileRom;
- if (!FileOpenRead(romFile, &fileRom)) {
- fprintf(stderr, "Failed to open input ROM '%s'\n", romFile);
- return 1;
- }
- size_t romSize = FileSize(&fileRom);
- uint8_t *rom = malloc(romSize);
- if (rom == NULL) {
- fprintf(stderr, "Failed to allocate buffer for '%s'\n", romFile);
- return 1;
- }
- if (FileRead(&fileRom, rom, romSize, 1) != 1) {
- fprintf(stderr, "Failed to read from '%s'\n", romFile);
- return 1;
- }
- FileClose(&fileRom);
-
-
- // --------------------- Set up ---------------------
- Header *pHeader = (Header*) rom;
- BuildInfo info;
- if (!CheckRegion(pHeader, &info)) return 1;
- if (!MakeDir(outDir)) return 1;
- if (!ChangeDir(outDir)) return 1;
-
-
- // --------------------- Extract ARM7 program ---------------------
- if (!ExtractArm7(rom, &pHeader->arm7)) return 1;
-
-
- // --------------------- Extract banner ---------------------
- Banner *pBanner = (Banner*) (rom + pHeader->bannerOffset);
- if (!ExtractBanner(pBanner, &info)) return 1;
-
-
- // --------------------- Extract assets ---------------------
- if (!MakeDir(ASSETS_SUBDIR)) return 1;
- if (!ChangeDir(ASSETS_SUBDIR)) return 1;
- const uint8_t *fntStart = rom + pHeader->fileNames.offset;
- const uint8_t *fatStart = rom + pHeader->fileAllocs.offset;
- if (!ExtractAssets(rom, fatStart, fntStart)) return 1;
- if (!ChangeDir("..")) return 1;
-
-
- // --------------------- Extract overlay data ---------------------
- if (!ExtractOverlayData(rom, pHeader)) return 1;
-
- if (!ChangeDir("..")) return 1;
-
- free(rom);
-}
diff --git a/tools/rom/files.h b/tools/rom/files.h
deleted file mode 100644
index 3b5d8863..00000000
--- a/tools/rom/files.h
+++ /dev/null
@@ -1,223 +0,0 @@
-#ifndef __FILES_H
-#define __FILES_H
-
-#include <ctype.h>
-
-#include "util.h"
-#include "rom.h"
-
-typedef struct FileTree {
- struct FileTree *children;
- uint16_t numChildren;
- uint16_t maxChildren;
- uint16_t firstFileId;
- bool addedToFat;
- FntSubEntry *entry;
-} FileTree;
-
-bool MakeFileTree(FileTree *pTree);
-
-bool IterFiles(bool (*callback)(const char *name, bool isDir, void*), void *userData) {
-#ifdef __UTIL_WINDOWS
- WIN32_FIND_DATAA findData;
- HANDLE hFind = FindFirstFileA("*", &findData);
- if (hFind == INVALID_HANDLE_VALUE) FATAL("Failed to open directory to iterate files\n");
- do {
- const char *name = findData.cFileName;
- if (strcmp(name, ".") == 0) continue;
- if (strcmp(name, "..") == 0) continue;
- bool isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
- if (!callback(name, isDir, userData)) return false;
- } while (FindNextFileA(hFind, &findData));
- FindClose(hFind);
-#elif defined(__UTIL_LINUX)
- DIR *dir = opendir(".");
- struct dirent *entry;
- while ((entry = readdir(dir)) != NULL) {
- const char *name = entry->d_name;
- if (strcmp(name, ".") == 0) continue;
- if (strcmp(name, "..") == 0) continue;
- bool isDir = entry->d_type == DT_DIR;
- if (!callback(name, isDir, userData)) return false;
- }
- closedir(dir);
-#endif
- return true;
-}
-
-bool _GrowFileTreeChildren(FileTree *pTree, size_t minChildren) {
- FileTree tree;
- memcpy(&tree, pTree, sizeof(tree));
- if (tree.maxChildren >= minChildren) return true;
-
- size_t newSize = tree.maxChildren;
- if (newSize == 0) newSize = minChildren;
- while (newSize < minChildren) newSize *= 2;
- if (tree.children == NULL) {
- FileTree *children = malloc(newSize * sizeof(FileTree));
- if (children == NULL) FATAL("Failed to allocate file tree children\n");
- tree.children = children;
- } else {
- FileTree *children = realloc(tree.children, newSize * sizeof(FileTree));
- if (children == NULL) FATAL("Failed to reallocate file tree children\n");
- tree.children = children;
- }
- tree.maxChildren = newSize;
-
- memcpy(pTree, &tree, sizeof(tree));
- return true;
-}
-
-bool _FileTreeFileCallback(const char *name, bool isDir, void *userData) {
- FileTree *pTree = (FileTree*) userData;
- size_t nameLength = strlen(name);
-
- if (isDir) {
- FntSubEntry *entry = malloc(sizeof(FntSubEntry) + nameLength + 2);
- if (entry == NULL) FATAL("Failed to allocate FNT sub entry for directory '%s'\n", name);
- entry->isSubdir = true;
- entry->length = nameLength;
- memcpy(entry->name, name, nameLength);
- WRITE_SUBDIR_ID(entry, 0);
-
- if (!ChangeDir(name)) return false;
-
- FileTree child;
- if (!MakeFileTree(&child)) return false;
- child.entry = entry;
- if (!_GrowFileTreeChildren(pTree, pTree->numChildren + 1)) return false;
- memcpy(&pTree->children[pTree->numChildren], &child, sizeof(child));
- pTree->numChildren += 1;
-
- if (!ChangeDir("..")) return false;
- } else {
- FntSubEntry *entry = malloc(sizeof(FntSubEntry) + nameLength);
- if (entry == NULL) FATAL("Failed to allocate FNT sub entry for file '%s'\n", name);
- entry->isSubdir = false;
- entry->length = nameLength;
- memcpy(entry->name, name, nameLength);
-
- FileTree child;
- child.children = NULL;
- child.numChildren = 0;
- child.maxChildren = 0;
- child.firstFileId = 0;
- child.addedToFat = false;
- child.entry = entry;
- if (!_GrowFileTreeChildren(pTree, pTree->numChildren + 1)) return false;
- memcpy(&pTree->children[pTree->numChildren], &child, sizeof(child));
- pTree->numChildren += 1;
- }
- return true;
-}
-
-bool MakeFileTree(FileTree *pTree) {
- FileTree tree;
- tree.children = NULL;
- tree.numChildren = 0;
- tree.maxChildren = 0;
- tree.addedToFat = false;
- if (!_GrowFileTreeChildren(&tree, 64)) return false;
- tree.entry = NULL;
-
- if (!IterFiles(_FileTreeFileCallback, &tree)) return false;
- memcpy(pTree, &tree, sizeof(tree));
- return true;
-}
-
-bool FreeFileTree(FileTree *pTree) {
- for (size_t i = 0; i < pTree->numChildren; ++i) {
- if (!FreeFileTree(&pTree->children[i])) return false;
- }
- if (pTree->children != NULL) {
- free(pTree->children);
- pTree->children = NULL;
- }
- pTree->numChildren = 0;
- pTree->maxChildren = 0;
- pTree->addedToFat = false;
- if (pTree->entry != NULL) {
- free(pTree->entry);
- pTree->entry = NULL;
- }
- return true;
-}
-
-int CompareFileTreeNormal(const void *a, const void *b) {
- FileTree *treeA = (FileTree*) a;
- FileTree *treeB = (FileTree*) b;
-
- // Files before directories
- bool dirA = treeA->entry == NULL || treeA->entry->isSubdir;
- bool dirB = treeB->entry == NULL || treeB->entry->isSubdir;
- if (dirA && !dirB) return 1;
- if (!dirA && dirB) return -1;
-
- size_t lenA = treeA->entry->length;
- size_t lenB = treeB->entry->length;
- size_t minSize = (lenA < lenB) ? lenA : lenB;
-
- // Alphabetic name order
- const char *nameA = treeA->entry->name;
- const char *nameB = treeB->entry->name;
- for (size_t i = 0; i < minSize; ++i) {
- const char chA = tolower(nameA[i]);
- const char chB = tolower(nameB[i]);
- if (chA != chB) return chA - chB;
- }
-
- // Shortest name first
- if (lenA < lenB) return -1;
- if (lenA > lenB) return 1;
- return 0;
-}
-
-int CompareFileTreeAscii(const void *a, const void *b) {
- FileTree *treeA = (FileTree*) a;
- FileTree *treeB = (FileTree*) b;
-
- size_t lenA = treeA->entry->length;
- size_t lenB = treeB->entry->length;
- size_t minSize = (lenA < lenB) ? lenA : lenB;
-
- // ASCII order
- int cmp = strncmp(treeA->entry->name, treeB->entry->name, minSize);
- if (cmp != 0) return cmp;
-
- // Shortest name first
- if (lenA < lenB) return -1;
- if (lenA > lenB) return 1;
- return 0;
-}
-
-bool SortFileTree(FileTree *pTree, int (*compare)(const void*, const void*)) {
- if (pTree->numChildren <= 1) return true;
- FileTree tree;
- memcpy(&tree, pTree, sizeof(tree));
-
- qsort(tree.children, tree.numChildren, sizeof(*tree.children), compare);
- for (size_t i = 0; i < tree.numChildren; ++i) {
- if (!SortFileTree(&tree.children[i], compare)) return false;
- }
-
- memcpy(pTree, &tree, sizeof(tree));
- return true;
-}
-
-FileTree* FindSubTree(FileTree *tree, const char *path) {
- if (*path == '/') ++path;
- const char *nextPath = strchr(path, '/');
- if (nextPath == NULL) return tree;
-
- size_t dirNameLen = nextPath - path;
- for (size_t i = 0; i < tree->numChildren; ++i) {
- FileTree *child = &tree->children[i];
- if (child->entry->length != dirNameLen) continue;
- if (strncmp(child->entry->name, path, dirNameLen) != 0) continue;
- return FindSubTree(child, nextPath);
- }
-
- return NULL;
-}
-
-#endif
diff --git a/tools/rom/ph.h b/tools/rom/ph.h
deleted file mode 100644
index 8cde8a52..00000000
--- a/tools/rom/ph.h
+++ /dev/null
@@ -1,42 +0,0 @@
-#ifndef __PH_H
-#define __PH_H
-
-#define TITLE "ZELDA_DS:PH"
-#define GAMECODE_PREFIX "AZE"
-
-#define BANNER_SUBDIR "banner"
-#define ICON_BITMAP_FILE BANNER_SUBDIR "/icon.bin"
-#define ICON_PALETTE_FILE BANNER_SUBDIR "/icon.pal"
-#define TITLE_JAP_FILE BANNER_SUBDIR "/title_jap.txt"
-#define TITLE_ENG_FILE BANNER_SUBDIR "/title_eng.txt"
-#define TITLE_FRE_FILE BANNER_SUBDIR "/title_fre.txt"
-#define TITLE_GER_FILE BANNER_SUBDIR "/title_ger.txt"
-#define TITLE_ITA_FILE BANNER_SUBDIR "/title_ita.txt"
-#define TITLE_SPA_FILE BANNER_SUBDIR "/title_spa.txt"
-
-#define ASSETS_SUBDIR "assets"
-
-#define ARM9_PROGRAM_FILE "arm9.lz"
-#define ARM9_FOOTER_FILE "arm9_footer.bin"
-#define ARM9_METADATA_FILE "arm9_metadata.bin"
-#define ARM9_OVERLAY_TABLE_FILE "arm9_ovt.bin"
-#define ARM9_OVERLAY_DATA_FILE "arm9_ovdata.bin"
-#define OVERLAYS_SUBDIR "overlays"
-
-#define ARM7_PROGRAM_FILE "arm7.bin"
-
-typedef enum {
- REGION_JAPAN = 'J',
- REGION_USA = 'E',
- REGION_EUROPE = 'P',
-} Region;
-
-typedef struct {
- Region region;
-} BuildInfo;
-
-typedef struct {
- uint32_t fileId;
-} OverlayData;
-
-#endif
diff --git a/tools/rom/rom.h b/tools/rom/rom.h
deleted file mode 100644
index 28a88850..00000000
--- a/tools/rom/rom.h
+++ /dev/null
@@ -1,124 +0,0 @@
-#ifndef __ROM_H
-#define __ROM_H
-
-#include <stdbool.h>
-#include <stddef.h>
-#include <stdint.h>
-
-#define SECURE_AREA_SIZE 0x4000
-
-typedef struct {
- /* 00 */ uint32_t offset;
- /* 04 */ uint32_t entry;
- /* 08 */ uint32_t baseAddr;
- /* 0c */ uint32_t size;
- /* 10 */
-} ProgramOffset;
-
-typedef struct {
- /* 0 */ uint32_t offset;
- /* 4 */ uint32_t size;
- /* 8 */
-} TableOffset;
-
-typedef struct {
- /* 0000 */ char title[0xc];
- /* 000c */ char gamecode[0x4];
- /* 0010 */ char makercode[0x2];
- /* 0012 */ uint8_t unitcode;
- /* 0013 */ uint8_t encSeedSelect;
- /* 0014 */ uint8_t capacity;
- /* 0015 */ uint8_t reserved0[0x8];
- /* 001d */ uint8_t dsRegion;
- /* 001e */ uint8_t romVersion;
- /* 001f */ uint8_t autostart;
- /* 0020 */ ProgramOffset arm9;
- /* 0030 */ ProgramOffset arm7;
- /* 0040 */ TableOffset fileNames;
- /* 0048 */ TableOffset fileAllocs;
- /* 0050 */ TableOffset arm9Overlays;
- /* 0058 */ TableOffset arm7Overlays;
- /* 0060 */ uint32_t normalCmdSetting;
- /* 0064 */ uint32_t key1CmdSetting;
- /* 0068 */ uint32_t bannerOffset;
- /* 006c */ uint16_t secureAreaCrc;
- /* 006e */ uint16_t secureAreaDelay;
- /* 0070 */ uint32_t arm9AutoloadCallback;
- /* 0074 */ uint32_t arm7AutoloadCallback;
- /* 0078 */ uint64_t secureAreaDisable;
- /* 0080 */ uint32_t romSize;
- /* 0084 */ uint32_t headerSize;
- /* 0088 */ uint32_t autoloadBlockInfosOffset;
- /* 008c */ uint8_t reserved1[0x8];
- /* 0094 */ uint16_t romEnd;
- /* 0096 */ uint16_t rwEnd;
- /* 0098 */ uint8_t reserved2[0x18];
- /* 00b0 */ uint8_t reserved3[0x10];
- /* 00c0 */ uint8_t logo[0x9c];
- /* 015c */ uint16_t logoCrc;
- /* 015e */ uint16_t headerCrc;
- /* 0160 */ uint32_t debugRomOffset;
- /* 0164 */ uint32_t debugSize;
- /* 0168 */ uint32_t debugRamAddr;
- /* 016c */ uint8_t reserved4[0x4];
- /* 0170 */ uint8_t reserved5[0x90];
- /* 0200 */ uint8_t reserved6[0xe00];
- /* 1000 */ uint8_t reserved7[0x3000];
- /* 4000 */
-} Header;
-
-typedef struct {
- /* 00 */ uint32_t id;
- /* 04 */ uint32_t baseAddr;
- /* 08 */ uint32_t textSize;
- /* 0c */ uint32_t bssSize;
- /* 10 */ uint32_t sinitStart;
- /* 14 */ uint32_t sinitEnd;
- /* 18 */ uint32_t fileId;
- /* 1c */ uint32_t compressedSize : 24;
- /* 1f */ uint32_t isCompressed : 8;
- /* 20 */
-} OverlayEntry;
-
-typedef struct {
- /* 0000 */ uint16_t version;
- /* 0002 */ uint16_t crc;
- /* 0004 */ uint8_t reserved0[0x1c];
- /* 0020 */ uint8_t iconBitmap[0x200];
- /* 0220 */ uint16_t iconPalette[0x10];
- /* 0240 */ wchar_t japaneseTitle[0x80];
- /* 0340 */ wchar_t englishTitle[0x80];
- /* 0440 */ wchar_t frenchTitle[0x80];
- /* 0540 */ wchar_t germanTitle[0x80];
- /* 0640 */ wchar_t italianTitle[0x80];
- /* 0740 */ wchar_t spanishTitle[0x80];
- /* 0540 */
-} Banner;
-
-typedef struct {
- /* 0 */ uint32_t subtableOffset;
- /* 4 */ uint16_t firstFile;
- /* 6 */ uint16_t parentId;
- /* 8 */
-} FntEntry;
-
-typedef struct {
- /* 0.0 */ uint8_t length : 7;
- /* 0.7 */ bool isSubdir : 1;
- /* 1.0 */ char name[];
- // If isSubdir
- /* 1.0 + length */ // uint16_t subdirId;
- /* 1.0 + length + 2 */
- // Else
- /* 1.0 + length */
-} FntSubEntry;
-
-#define READ_SUBDIR_ID(entry) READ16(entry + sizeof(*entry) + entry->length);
-#define WRITE_SUBDIR_ID(entry,id) WRITE16(entry + sizeof(*entry) + entry->length, id)
-
-typedef struct {
- /* 0 */ uint32_t startOffset;
- /* 4 */ uint32_t endOffset;
-} FatEntry;
-
-#endif