diff --git a/tools/rom/util.h b/tools/include/util.h similarity index 61% rename from tools/rom/util.h rename to tools/include/util.h index a757278a..d1cc32fe 100644 --- a/tools/rom/util.h +++ b/tools/include/util.h @@ -6,7 +6,8 @@ #include #include -#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); diff --git a/tools/rom/Makefile b/tools/rom/Makefile index 3cd63d49..201c69b0 100644 --- a/tools/rom/Makefile +++ b/tools/rom/Makefile @@ -1,5 +1,5 @@ CC := gcc -CFLAGS := -g -Wall +CFLAGS := -g -Wall -I../include ifneq ($(DEBUG),1) CFLAGS += -O2 -DNDEBUG diff --git a/tools/rom/build.c b/tools/rom/build.c index 8e799710..20eadb0b 100644 --- a/tools/rom/build.c +++ b/tools/rom/build.c @@ -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); } diff --git a/tools/rom/extract.c b/tools/rom/extract.c index c236b5f8..b677b76c 100644 --- a/tools/rom/extract.c +++ b/tools/rom/extract.c @@ -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 ---------------------