Use Win32 file API in rom tools

This commit is contained in:
Aetias
2024-02-23 19:44:22 +01:00
parent ea8b5522e7
commit f37bc0c47e
4 changed files with 272 additions and 170 deletions
+117 -1
View File
@@ -6,7 +6,8 @@
#include <stdio.h>
#include <string.h>
#define FATAL(...) do { fprintf(stderr, __VA_ARGS__); return false; } while (0)
#define PRINT_FATAL(...) fprintf(stderr, __VA_ARGS__)
#define FATAL(...) do { PRINT_FATAL(__VA_ARGS__); return false; } while (0)
#define WRITE16(buf,val) do { ((uint8_t*) buf)[0] = (val) & 0xFF; ((uint8_t*) buf)[1] = ((val) >> 8) & 0xFF; } while (0)
#define WRITE24(buf,val) do { ((uint8_t*) buf)[0] = (val) & 0xFF; ((uint8_t*) buf)[1] = ((val) >> 8) & 0xFF; ((uint8_t*) buf)[2] = ((val) >> 16) & 0xFF; } while (0)
@@ -65,6 +66,121 @@ bool ChangeDir(const char *dir) {
FATAL("Failed to enter directory '%s' from current directory '%s'\n", dir, cwd);
}
typedef struct {
const char *name;
#ifdef __UTIL_WINDOWS
HFILE handle;
#elif defined(__UTIL_LINUX)
FILE *fp;
#endif
} File;
bool FileOpenRead(const char *name, File *file) {
#ifdef __UTIL_WINDOWS
HFILE handle = CreateFileA(name, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE) {
file->name = name;
file->handle = handle;
return true;
}
#elif defined(__UTIL_LINUX)
FILE *fp = fopen(name, "rb");
if (fp != NULL) {
file->name = name;
file->fp = fp;
return true;
}
#endif
FATAL("Failed to open file '%s' for reading\n", name);
}
bool FileOpenWrite(const char *name, File *file) {
#ifdef __UTIL_WINDOWS
HFILE handle = CreateFileA(name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (handle != INVALID_HANDLE_VALUE) {
file->name = name;
file->handle = handle;
return true;
}
#elif defined(__UTIL_LINUX)
FILE *fp = fopen(name, "wb");
if (fp != NULL) {
file->name = name;
file->fp = fp;
return true;
}
#endif
FATAL("Failed to open file '%s' for writing\n", name);
}
void FileClose(File *file) {
#ifdef __UTIL_WINDOWS
CloseHandle(file->handle);
file->name = NULL;
file->handle = NULL;
#elif defined(__UTIL_LINUX)
fclose(file->fp);
file->name = NULL;
file->fp = NULL;
#endif
}
size_t FileRead(const File *file, void *buf, size_t size, size_t count) {
#ifdef __UTIL_WINDOWS
DWORD bytesRead;
if (ReadFile(file->handle, buf, size * count, &bytesRead, NULL)) return true;
if (bytesRead > 0) return bytesRead / size;
#elif defined(__UTIL_LINUX)
size_t countRead = fread(buf, size, count, file->fp);
if (countRead > 0) return countRead;
#endif
PRINT_FATAL("Failed to read %ld * %ld bytes from '%s'\n", count, size, file->name);
return 0;
}
bool FileWrite(const File *file, const void *buf, size_t size, size_t count) {
#ifdef __UTIL_WINDOWS
if (WriteFile(file->handle, buf, size * count, NULL, NULL)) return true;
#elif defined(__UTIL_LINUX)
if (fwrite(buf, size, count, file->fp) == count) return true;
#endif
FATAL("Failed to write %ld * %ld bytes to '%s'\n", count, size, file->name);
}
size_t FileSize(const File *file) {
#ifdef __UTIL_WINDOWS
DWORD sizeHigh;
DWORD sizeLow = GetFileSize(file->handle, &sizeHigh);
return sizeLow | (sizeHigh << 32);
#elif defined(__UTIL_LINUX)
size_t pos = ftell(file->fp);
fseek(file->fp, 0, SEEK_END);
size_t size = ftell(file->fp);
fseek(file->fp, pos, SEEK_SET);
return size;
#endif
}
size_t FileOffset(const File *file) {
#ifdef __UTIL_WINDOWS
DWORD offsetHigh = 0;
DWORD offsetLow = SetFilePointer(file->handle, 0, &offsetHigh, FILE_CURRENT);
return offsetLow | (offsetHigh << 32);
#elif defined(__UTIL_LINUX)
return ftell(file->fp);
#endif
}
void FileGoTo(const File *file, size_t offset) {
#ifdef __UTIL_WINDOWS
DWORD offsetHigh = offset >> 32;
DWORD offsetLow = offset & 0xffffffff;
SetFilePointer(file->handle, offsetHigh, &offsetHigh, FILE_BEGIN);
#elif defined(__UTIL_LINUX)
fseek(file->fp, offset, SEEK_SET);
#endif
}
bool WcharToUtf8(wchar_t *in, size_t inSize, char *out, size_t outSize, size_t *pResultSize) {
#ifdef __UTIL_WINDOWS
size_t resultSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, in, inSize / sizeof(wchar_t), out, outSize, NULL, NULL);
+1 -1
View File
@@ -1,5 +1,5 @@
CC := gcc
CFLAGS := -g -Wall
CFLAGS := -g -Wall -I../include
ifneq ($(DEBUG),1)
CFLAGS += -O2 -DNDEBUG
+121 -132
View File
@@ -8,7 +8,7 @@
#include "util.h"
#include "files.h"
#define VERSION "1.1"
#define VERSION "1.1.1"
#define BUFFER_SIZE 1024 * 1024
uint8_t *readBuffer = NULL;
@@ -201,10 +201,10 @@ typedef struct {
} Arm9Metadata;
bool LoadArm9Metadata(Arm9Metadata *pMetadata) {
FILE *fp = fopen(ARM9_METADATA_FILE, "rb");
if (fp == NULL) FATAL("Failed to open ARM9 metadata '" ARM9_METADATA_FILE "'\n");
if (fread(pMetadata, sizeof(*pMetadata), 1, fp) != 1) FATAL("Failed to read ARM9 metadata '" ARM9_METADATA_FILE "'\n");
fclose(fp);
File file;
if (!FileOpenRead(ARM9_METADATA_FILE, &file)) return false;
if (FileRead(&file, pMetadata, sizeof(*pMetadata), 1) == 0) return false;
FileClose(&file);
return true;
}
@@ -212,11 +212,9 @@ bool LoadArm9Metadata(Arm9Metadata *pMetadata) {
// 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 *fp = fopen(filePath, "rb");
if (fp == NULL) FATAL("Failed to open file '%s'\n", filePath);
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
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);
@@ -224,41 +222,39 @@ bool ReadFileAlloc(const char *filePath, uint8_t **pBuffer, uint32_t *pFileSize)
uint8_t *end = buffer + size;
while (current < end) {
size_t bytesRead = fread(current, 1, BUFFER_SIZE, fp);
if (bytesRead == 0) FATAL("Failed to read from file '%s'\n", filePath);
size_t bytesRead = FileRead(&file, current, 1, BUFFER_SIZE);
if (bytesRead == 0) return false;
current += bytesRead;
}
fclose(fp);
FileClose(&file);
*pBuffer = buffer;
if (pFileSize != NULL) *pFileSize = size;
return true;
}
bool AppendFile(FILE *fpRom, const char *filePath, size_t *pAddress, uint32_t *pFileSize) {
bool AppendFile(File *rom, const char *filePath, size_t *pAddress, uint32_t *pFileSize) {
assert(readBuffer != NULL);
FILE *fp = fopen(filePath, "rb");
if (fp == NULL) FATAL("Failed to open file '%s'\n", filePath);
fseek(fp, 0, SEEK_END);
size_t size = ftell(fp);
fseek(fp, 0, SEEK_SET);
File file;
if (!FileOpenRead(filePath, &file)) return false;
size_t size = FileSize(&file);
size_t bytesWritten = 0;
while (bytesWritten < size) {
size_t bytesRead = fread(readBuffer, 1, BUFFER_SIZE, fp);
if (bytesRead == 0) FATAL("Failed to read from file '%s'\n", filePath);
if (fwrite(readBuffer, bytesRead, 1, fpRom) != 1) FATAL("Failed to write file '%s' to output ROM\n", filePath);
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;
}
fclose(fp);
FileClose(&file);
*pAddress += size;
if (pFileSize != NULL) *pFileSize = size;
return true;
}
bool WriteArm9Program(FILE *fpRom, size_t *pAddress, uint32_t *pFileSize, uint32_t *pSecureArea, const Arm9Metadata *metadata) {
bool WriteArm9Program(File *rom, size_t *pAddress, uint32_t *pFileSize, uint32_t *pSecureArea, const Arm9Metadata *metadata) {
size_t address = *pAddress;
uint8_t *arm9;
@@ -278,7 +274,7 @@ bool WriteArm9Program(FILE *fpRom, size_t *pAddress, uint32_t *pFileSize, uint32
memcpy(&arm9[offset], &compressedCodeEnd, sizeof(compressedCodeEnd));
offset += compressedCodeEnd;
if (fwrite(arm9, fileSize, 1, fpRom) != 1) FATAL("Failed to write ARM9 program\n");
if (!FileWrite(rom, arm9, fileSize, 1)) FATAL("Failed to write ARM9 program\n");
address += fileSize;
memcpy(pSecureArea, arm9, SECURE_AREA_SIZE);
@@ -289,22 +285,23 @@ bool WriteArm9Program(FILE *fpRom, size_t *pAddress, uint32_t *pFileSize, uint32
return true;
}
bool Align(size_t alignment, FILE *fpRom, size_t *pAddress) {
bool Align(size_t alignment, File *rom, size_t *pAddress) {
assert((alignment & (alignment - 1)) == 0);
size_t mask = alignment - 1;
size_t address = ftell(fpRom);
size_t address = FileOffset(rom);
size_t nextAddr = (address + mask) & ~mask;
char padValue = 0xff;
while (address < nextAddr) {
if (fputc(0xff, fpRom) == -1) FATAL("Failed to pad output ROM at address 0x%lx\n", address);
address += 1;
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 *fpRom,
File *rom,
size_t *pAddress,
Header *pHeader,
const char *overlayDataFile,
@@ -314,39 +311,36 @@ bool WriteArm9OverlayTable(
) {
size_t address = *pAddress;
FILE *fp = fopen(ARM9_OVERLAY_TABLE_FILE, "rb");
if (fp == NULL) FATAL("Failed to open ARM9 overlay table '" ARM9_OVERLAY_TABLE_FILE "'\n");
fseek(fp, 0, SEEK_END);
size_t tableSize = ftell(fp);
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);
fseek(fp, 0, SEEK_SET);
OverlayEntry *entries = malloc(tableSize);
if (entries == NULL) FATAL("Failed to allocate array for ARM9 overlay table entries");
if (fread(entries, tableSize, 1, fp) != 1) FATAL("Failed to read ARM9 overlay table '" ARM9_OVERLAY_TABLE_FILE "'\n");
fclose(fp);
if (FileRead(&file, entries, tableSize, 1) == 0) FATAL("Failed to read ARM9 overlay table '" ARM9_OVERLAY_TABLE_FILE "'\n");
FileClose(&file);
fp = fopen(overlayDataFile, "rb");
if (fp == NULL) FATAL("Failed to open ARM9 overlay data file '%s'\n", overlayDataFile);
fseek(fp, 0, SEEK_END);
size_t dataSize = ftell(fp);
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));
}
fseek(fp, 0, SEEK_SET);
OverlayData *data = malloc(dataSize);
if (data == NULL) FATAL("Failed to allocate array for ARM9 overlay data entries\n");
if (fread(data, dataSize, 1, fp) != 1) FATAL("Failed to read ARM9 overlay data '%s'\n", overlayDataFile);
fclose(fp);
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 (fwrite(entries, tableSize, 1, fpRom) != 1) FATAL("Failed to write ARM9 overlay table\n");
if (!FileWrite(rom, entries, tableSize, 1)) FATAL("Failed to write ARM9 overlay table\n");
*pAddress = address;
*pEntries = entries;
@@ -357,7 +351,7 @@ bool WriteArm9OverlayTable(
}
bool WriteArm9OverlayFiles(
FILE *fpRom,
File *rom,
size_t *pAddress,
size_t numOverlays,
FatEntry *fatEntries,
@@ -371,10 +365,10 @@ bool WriteArm9OverlayFiles(
for (size_t ovNum = 0; ovNum < numOverlays; ++ovNum) {
sprintf(fileName, "ov%02ld.lz", ovNum);
if (!Align(512, fpRom, &address)) return false;
if (!Align(512, rom, &address)) return false;
size_t startOffset = address;
uint32_t fileSize = 0;
if (!AppendFile(fpRom, fileName, &address, &fileSize)) return false;
if (!AppendFile(rom, fileName, &address, &fileSize)) return false;
table[ovNum].compressedSize = fileSize;
table[ovNum].isCompressed = true;
uint32_t fileId = data[ovNum].fileId;
@@ -389,16 +383,16 @@ bool WriteArm9OverlayFiles(
return true;
}
bool RewriteArm9OverlayTable(FILE *fpRom, const Header *header, OverlayEntry *entries, size_t numEntries) {
size_t prevAddress = ftell(fpRom);
fseek(fpRom, header->arm9Overlays.offset, SEEK_SET);
if (fwrite(entries, sizeof(*entries), numEntries, fpRom) != numEntries) FATAL("Failed to rewrite ARM9 overlay table\n");
fseek(fpRom, prevAddress, SEEK_SET);
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 *fpRom,
File *rom,
size_t *pAddress,
Header *pHeader,
const char *overlayDataFile,
@@ -410,9 +404,9 @@ bool WriteArm9Overlays(
OverlayEntry *entries;
OverlayData *data;
size_t numOverlays;
if (!WriteArm9OverlayTable(fpRom, &address, pHeader, overlayDataFile, &entries, &data, &numOverlays)) return false;
if (!WriteArm9OverlayFiles(fpRom, &address, numOverlays, fatEntries, entries, data)) return false;
if (!RewriteArm9OverlayTable(fpRom, pHeader, entries, numOverlays)) return false;
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);
@@ -539,7 +533,7 @@ bool WriteFntSubtable(FileTree *tree, FntContext *pContext) {
return true;
}
bool WriteFnt(FILE *fpRom, size_t *pAddress, FileTree *pRoot, size_t firstFileId, size_t *pNumFiles) {
bool WriteFnt(File *rom, size_t *pAddress, FileTree *pRoot, size_t firstFileId, size_t *pNumFiles) {
size_t address = *pAddress;
FntContext ctx;
@@ -567,9 +561,9 @@ bool WriteFnt(FILE *fpRom, size_t *pAddress, FileTree *pRoot, size_t firstFileId
for (size_t i = 0; i < ctx.tableSize; ++i) {
ctx.table[i].subtableOffset += tableLength;
}
if (fwrite(ctx.table, sizeof(FntEntry), ctx.tableSize, fpRom) != ctx.tableSize) FATAL("Failed to write FNT table\n");
if (!FileWrite(rom, ctx.table, sizeof(FntEntry), ctx.tableSize)) FATAL("Failed to write FNT table\n");
address += ctx.tableSize * sizeof(FntEntry);
if (fwrite(ctx.subtable, ctx.subtableSize, 1, fpRom) != 1) FATAL("Failed to write FNT subtables\n");
if (!FileWrite(rom, ctx.subtable, ctx.subtableSize, 1)) FATAL("Failed to write FNT subtables\n");
address += ctx.subtableSize;
free(ctx.table);
@@ -580,14 +574,14 @@ bool WriteFnt(FILE *fpRom, size_t *pAddress, FileTree *pRoot, size_t firstFileId
return true;
}
bool WriteFat(FILE *fpRom, size_t *pAddress, size_t numFiles) {
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 (fwrite(&blank, sizeof(blank), 1, fpRom) != 1) FATAL("Failed to write blank placeholder FAT entry\n");
if (!FileWrite(rom, &blank, sizeof(blank), 1)) FATAL("Failed to write blank placeholder FAT entry\n");
}
address += sizeof(blank) * numFiles;
@@ -595,47 +589,43 @@ bool WriteFat(FILE *fpRom, size_t *pAddress, size_t numFiles) {
return true;
}
bool ReadTitle(const char *language, const char *file, wchar_t *title, size_t titleSize) {
bool ReadTitle(const char *language, const char *titleFile, wchar_t *title, size_t titleSize) {
char buf[1024];
memset(buf, 0, sizeof(buf));
FILE *fp = fopen(file, "rb");
if (fp == NULL) FATAL("Failed to open %s banner title '%s'\n", language, file);
File file;
if (!FileOpenRead(titleFile, &file)) FATAL("Failed to open %s banner title '%s'\n", language, titleFile);
fseek(fp, 0, SEEK_END);
size_t fileSize = ftell(fp);
if (fileSize > sizeof(buf) - 1) FATAL("Buffer too small for %s banner title '%s'\n", language, file);
fseek(fp, 0, SEEK_SET);
size_t fileSize = FileSize(&file);
if (fileSize > sizeof(buf) - 1) FATAL("Buffer too small for %s banner title '%s'\n", language, titleFile);
if (fread(buf, fileSize, 1, fp) != 1) FATAL("Failed to read %s banner title '%s'\n", language, file);
fclose(fp);
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 *fpRom, size_t *pAddress) {
bool WriteBanner(File *rom, size_t *pAddress) {
size_t address = *pAddress;
FILE *fp;
File file;
Banner banner;
banner.version = 1;
memset(banner.reserved0, 0, sizeof(banner.reserved0));
fp = fopen(ICON_BITMAP_FILE, "rb");
if (fp == NULL) FATAL("Failed to open banner icon bitmap '" ICON_BITMAP_FILE "'\n");
if (fread(banner.iconBitmap, sizeof(banner.iconBitmap), 1, fp) != 1) {
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");
}
fclose(fp);
FileClose(&file);
fp = fopen(ICON_PALETTE_FILE, "rb");
if (fp == NULL) FATAL("Failed to open banner icon palette '" ICON_PALETTE_FILE "'\n");
if (fread(banner.iconPalette, sizeof(banner.iconPalette), 1, fp) != 1) {
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");
}
fclose(fp);
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;
@@ -648,14 +638,14 @@ bool WriteBanner(FILE *fpRom, size_t *pAddress) {
uint8_t *crcEnd = (uint8_t*) &banner + sizeof(banner);
banner.crc = Crc(crcStart, crcEnd - crcStart);
if (fwrite(&banner, sizeof(banner), 1, fpRom) != 1) FATAL("Failed to write banner\n");
if (!FileWrite(rom, &banner, sizeof(banner), 1)) FATAL("Failed to write banner\n");
address += sizeof(banner);
*pAddress = address;
return true;
}
bool TraverseAndAppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *tree, FatEntry *entries, uint16_t firstFileId) {
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) {
@@ -666,16 +656,16 @@ bool TraverseAndAppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *tree
strncpy(name, entry->name, entry->length);
name[entry->length] = '\0';
if (!entry->isSubdir) {
if (!Align(512, fpRom, &address)) return false;
if (!Align(512, rom, &address)) return false;
size_t startOffset = address;
if (!AppendFile(fpRom, name, &address, NULL)) return false;
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(fpRom, &address, child, entries, child->firstFileId)) return false;
if (!TraverseAndAppendAssets(rom, &address, child, entries, child->firstFileId)) return false;
if (!ChangeDir("..")) return false;
}
@@ -684,7 +674,7 @@ bool TraverseAndAppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *tree
}
bool AppendAssets(
FILE *fpRom,
File *rom,
size_t *pAddress,
FileTree *root,
FatEntry *entries,
@@ -694,20 +684,18 @@ bool AppendAssets(
size_t address = *pAddress;
if (assetsListFile == NULL) {
if (!TraverseAndAppendAssets(fpRom, &address, root, entries, numOverlays)) return false;
if (!TraverseAndAppendAssets(rom, &address, root, entries, numOverlays)) return false;
*pAddress = address;
return true;
}
FILE *fp = fopen(assetsListFile, "rb");
if (fp == NULL) FATAL("Failed to open assets list file '%s'\n", assetsListFile);
fseek(fp, 0, SEEK_END);
size_t listSize = ftell(fp);
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);
fseek(fp, 0, SEEK_SET);
if (fread(assetsList, listSize, 1, fp) != 1) FATAL("Failed to read from assets list file '%s'\n", assetsListFile);
fclose(fp);
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];
@@ -724,7 +712,7 @@ bool AppendAssets(
uint16_t firstFileId = subTree->entry == NULL ? numOverlays : subTree->firstFileId;
if (path[1] != '\0' && !ChangeDir(&path[1])) return false;
if (!TraverseAndAppendAssets(fpRom, &address, subTree, entries, firstFileId)) return false;
if (!TraverseAndAppendAssets(rom, &address, subTree, entries, firstFileId)) return false;
if (!ChangeDir(assetsDir)) return false;
subTree->addedToFat = true;
@@ -736,24 +724,25 @@ bool AppendAssets(
return true;
}
bool RewriteFat(FILE *fpRom, size_t fatStart, const FatEntry *entries, size_t numFiles) {
fseek(fpRom, fatStart, SEEK_SET);
if (fwrite(entries, sizeof(*entries), numFiles, fpRom) != numFiles) FATAL("Failed to rewrite FAT table\n");
fseek(fpRom, 0, SEEK_END);
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 *fpRom, Header *pHeader, const char *arm7bios, uint32_t *secureArea, const Arm9Metadata *metadata) {
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 *fp = fopen(arm7bios, "rb");
if (fp == NULL) FATAL("Failed to open ARM7 BIOS '%s'\n", arm7bios);
fseek(fp, 0x30, SEEK_SET);
File file;
if (!FileOpenRead(arm7bios, &file)) FATAL("Failed to open ARM7 BIOS '%s'\n", arm7bios);
FileGoTo(&file, 0x30);
uint8_t encKey[sizeof(Blowfish)];
if (fread(&encKey, sizeof(encKey), 1, fp) != 1) FATAL("Failed to read encrypion key\n");
fclose(fp);
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) {
@@ -773,13 +762,13 @@ bool FinalizeHeader(FILE *fpRom, Header *pHeader, const char *arm7bios, uint32_t
header.headerCrc = Crc(&header, offsetof(Header, headerCrc));
size_t prevPos = ftell(fpRom);
fseek(fpRom, 0, SEEK_SET);
if (fwrite(&header, sizeof(header), 1, fpRom) != 1) {
size_t prevPos = FileOffset(rom);
FileGoTo(rom, 0);
if (!FileWrite(rom, &header, sizeof(header), 1)) {
fprintf(stderr, "Failed to rewrite header\n");
return 1;
}
fseek(fpRom, prevPos, SEEK_SET);
FileGoTo(rom, prevPos);
memcpy(pHeader, &header, sizeof(header));
return true;
@@ -889,8 +878,8 @@ int main(int argc, char **argv) {
return 1;
}
FILE *fpRom = fopen(romFile, "wb");
if (fpRom == NULL) {
File rom;
if (!FileOpenWrite(romFile, &rom)) {
fprintf(stderr, "Failed to open output ROM file '%s'\n", romFile);
return 1;
}
@@ -912,7 +901,7 @@ int main(int argc, char **argv) {
Header header;
InitHeader(&header, &info);
if (fwrite(&header, sizeof(header), 1, fpRom) != 1) {
if (!FileWrite(&rom, &header, sizeof(header), 1)) {
fprintf(stderr, "Failed to write NDS header\n");
return 1;
}
@@ -930,22 +919,22 @@ int main(int argc, char **argv) {
// --------------------- Write ARM9 program ---------------------
if (!ChangeDir(buildDir)) return 1;
if (!Align(512, fpRom, &address)) 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(fpRom, &address, &header.arm9.size, secureArea, &metadata)) return 1;
if (!AppendFile(fpRom, ARM9_FOOTER_FILE, &address, NULL)) return 1;
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, fpRom, &address)) return 1;
if (!Align(512, &rom, &address)) return 1;
header.arm9Overlays.offset = address;
size_t numOverlays = 0;
FatEntry overlayEntries[MAX_OVERLAYS];
if (!WriteArm9Overlays(fpRom, &address, &header, arm9overlayDataFile, overlayEntries, &numOverlays)) return 1;
if (!WriteArm9Overlays(&rom, &address, &header, arm9overlayDataFile, overlayEntries, &numOverlays)) return 1;
FreeFullPath(&arm9overlayDataFile);
if (!ChangeDir(rootDir)) return 1;
@@ -954,9 +943,9 @@ int main(int argc, char **argv) {
// --------------------- Write ARM7 program ---------------------
if (!Align(512, fpRom, &address)) return 1;
if (!Align(512, &rom, &address)) return 1;
header.arm7.offset = address;
if (!AppendFile(fpRom, ARM7_PROGRAM_FILE, &address, &header.arm7.size)) return 1;
if (!AppendFile(&rom, ARM7_PROGRAM_FILE, &address, &header.arm7.size)) return 1;
if (!ChangeDir(ASSETS_SUBDIR)) return 1;
@@ -966,17 +955,17 @@ int main(int argc, char **argv) {
if (!MakeFileTree(&root)) return false;
if (!SortFileTree(&root, CompareFileTreeNormal)) return false;
if (!Align(512, fpRom, &address)) return 1;
if (!Align(512, &rom, &address)) return 1;
size_t numFiles = 0;
header.fileNames.offset = address;
if (!WriteFnt(fpRom, &address, &root, numOverlays, &numFiles)) return 1;
if (!WriteFnt(&rom, &address, &root, numOverlays, &numFiles)) return 1;
header.fileNames.size = address - header.fileNames.offset;
// --------------------- Write file allocation table (FAT) ---------------------
if (!Align(512, fpRom, &address)) return 1;
if (!Align(512, &rom, &address)) return 1;
header.fileAllocs.offset = address;
if (!WriteFat(fpRom, &address, numFiles)) return 1;
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));
@@ -985,20 +974,20 @@ int main(int argc, char **argv) {
// --------------------- Write banner ---------------------
if (!Align(512, fpRom, &address)) return false;
if (!Align(512, &rom, &address)) return false;
header.bannerOffset = address;
if (!WriteBanner(fpRom, &address)) return false;
if (!WriteBanner(&rom, &address)) return false;
if (!ChangeDir(ASSETS_SUBDIR)) return 1;
// --------------------- Write assets ---------------------
if (!Align(512, fpRom, &address)) return false;
if (!Align(512, &rom, &address)) return false;
if (!SortFileTree(&root, CompareFileTreeAscii)) return false;
if (!AppendAssets(fpRom, &address, &root, fatEntries, numOverlays, assetsListFile)) return false;
if (!AppendAssets(&rom, &address, &root, fatEntries, numOverlays, assetsListFile)) return false;
if (assetsListFile != NULL) FreeFullPath(&assetsListFile);
if (!RewriteFat(fpRom, header.fileAllocs.offset, fatEntries, numFiles))
if (!RewriteFat(&rom, header.fileAllocs.offset, fatEntries, numFiles))
free(fatEntries);
if (!FreeFileTree(&root)) return false;
@@ -1012,7 +1001,7 @@ int main(int argc, char **argv) {
header.romSize = address;
header.capacity = 15 - __builtin_clz(header.romSize);
size_t romEnd = 1 << (17 + header.capacity);
if (!Align(romEnd, fpRom, &address)) return 1;
if (!Align(romEnd, &rom, &address)) return 1;
// --------------------- Update header ---------------------
@@ -1021,11 +1010,11 @@ int main(int argc, char **argv) {
if (!ChangeDir(buildDir)) return 1;
if (!FinalizeHeader(fpRom, &header, arm7bios, secureArea, &metadata)) return false;
if (!FinalizeHeader(&rom, &header, arm7bios, secureArea, &metadata)) return false;
FreeFullPath(&arm7bios);
if (!ChangeDir(rootDir)) return 1;
free(readBuffer);
fclose(fpRom);
FileClose(&rom);
}
+33 -36
View File
@@ -8,7 +8,7 @@
#include "ph.h"
#include "util.h"
#define VERSION "1.0.1"
#define VERSION "1.0.2"
#define INDENT 4
// Command line flags for debugging purposes
@@ -41,43 +41,42 @@ bool CheckRegion(const Header *pHeader, BuildInfo *pInfo) {
}
bool ExtractArm7(const uint8_t *rom, ProgramOffset *pArm7) {
FILE *fp = fopen(ARM7_PROGRAM_FILE, "wb");
if (fp == NULL) FATAL("Failed to create ARM7 program '" ARM7_PROGRAM_FILE "'\n");
if (fwrite(rom + pArm7->offset, pArm7->size, 1, fp) != 1) FATAL("Failed to write ARM7 program '" ARM7_PROGRAM_FILE "'\n");
fclose(fp);
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 *file, const wchar_t *title, size_t titleSize) {
bool ExtractTitle(const char *language, const char *fileName, const wchar_t *title, size_t titleSize) {
char buf[1024];
FILE *fp = fopen(file, "wb");
if (fp == NULL) FATAL("Failed to create %s banner title '%s'\n", language, file);
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;
if (fputs(buf, fp) == -1) FATAL("Failed to write %s banner title '%s'\n", language, file);
fclose(fp);
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 *fp;
File file;
fp = fopen(ICON_BITMAP_FILE, "wb");
if (fp == NULL) FATAL("Failed to create banner icon bitmap '" ICON_BITMAP_FILE "'\n");
if (fwrite(pBanner->iconBitmap, sizeof(pBanner->iconBitmap), 1, fp) != 1) {
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");
}
fclose(fp);
FileClose(&file);
fp = fopen(ICON_PALETTE_FILE, "wb");
if (fp == NULL) FATAL("Failed to create banner icon palette '" ICON_PALETTE_FILE "'\n");
if (fwrite(pBanner->iconPalette, sizeof(pBanner->iconPalette), 1, fp) != 1) {
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");
}
fclose(fp);
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;
@@ -147,10 +146,10 @@ bool ExtractSubtable(
size_t fileSize = pFatEntry->endOffset - pFatEntry->startOffset;
const uint8_t *pFileBytes = rom + pFatEntry->startOffset;
FILE *fp = fopen(name, "wb");
if (fp == NULL) FATAL("Failed to open assets file '%s'\n", name);
if (fwrite(pFileBytes, fileSize, 1, fp) != 1) FATAL("Failed to write to assets file '%s'\n", name);
fclose(fp);
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;
@@ -271,17 +270,17 @@ 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 *fp = fopen(ARM9_OVERLAY_DATA_FILE, "wb");
if (fp == NULL) FATAL("Failed to open overlay data file '" ARM9_OVERLAY_DATA_FILE "'\n");
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 (fwrite(&data, sizeof(data), 1, fp) != 1) {
FATAL("Failed to write overlay data to '" ARM9_OVERLAY_DATA_FILE "'\n");
}
if (!FileWrite(&file, &data, sizeof(data), 1)) FATAL("Failed to write overlay data to '" ARM9_OVERLAY_DATA_FILE "'\n");
}
fclose(fp);
FileClose(&file);
return true;
}
@@ -343,24 +342,22 @@ int main(int argc, const char **argv) {
// --------------------- Load ROM ---------------------
FILE *fpRom = fopen(romFile, "rb");
if (fpRom == NULL) {
File fileRom;
if (!FileOpenRead(romFile, &fileRom)) {
fprintf(stderr, "Failed to open input ROM '%s'\n", romFile);
return 1;
}
fseek(fpRom, 0, SEEK_END);
size_t romSize = ftell(fpRom);
fseek(fpRom, 0, SEEK_SET);
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 (fread(rom, romSize, 1, fpRom) != 1) {
if (FileRead(&fileRom, rom, romSize, 1) != 1) {
fprintf(stderr, "Failed to read from '%s'\n", romFile);
return 1;
}
fclose(fpRom);
FileClose(&fileRom);
// --------------------- Set up ---------------------