From eed711303a4b564eaab5532362dea976f19b0d53 Mon Sep 17 00:00:00 2001 From: Aetias Date: Sun, 15 Oct 2023 17:51:46 +0200 Subject: [PATCH] Write banner --- tools/rom/build.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++ tools/rom/util.h | 61 ++++++++++------------------------------- 2 files changed, 84 insertions(+), 47 deletions(-) diff --git a/tools/rom/build.c b/tools/rom/build.c index 268779ca..d1ea3ca3 100644 --- a/tools/rom/build.c +++ b/tools/rom/build.c @@ -345,6 +345,62 @@ 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) { + 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); + + 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); + + if (fread(buf, fileSize, 1, fp) != 1) FATAL("Failed to read %s banner title '%s'\n", language, file); + fclose(fp); + + if (!Utf8ToWchar(buf, fileSize, title, titleSize)) return false; + return true; +} + +bool WriteBanner(FILE *fpRom, size_t *pAddress) { + size_t address = *pAddress; + + FILE *fp; + + Banner banner; + banner.version = 1; + banner.crc; + 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) { + FATAL("Failed to read banner icon bitmap '" ICON_BITMAP_FILE "'\n"); + } + fclose(fp); + + 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) { + FATAL("Failed to read banner icon palette '" ICON_PALETTE_FILE "'\n"); + } + fclose(fp); + + 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; + + if (fwrite(&banner, sizeof(banner), 1, fpRom) != 1) FATAL("Failed to write banner\n"); + address += sizeof(banner); + + *pAddress = address; + return true; +} + bool AppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *tree, FatEntry *entries) { size_t address = *pAddress; @@ -552,6 +608,20 @@ int main(int argc, const char **argv) { FatEntry *fatEntries = malloc(numFiles * sizeof(FatEntry)); memcpy(fatEntries, overlayEntries, numOverlays * sizeof(*fatEntries)); + if (chdir("..") != 0) { + fprintf(stderr, "Failed to leave assets directory '" ASSETS_SUBDIR "'\n"); + return 1; + } + + if (!Align(256, fpRom, &address)) return false; + header.bannerOffset = address; + if (!WriteBanner(fpRom, &address)) return false; + + if (chdir(ASSETS_SUBDIR) != 0) { + fprintf(stderr, "Failed to enter assets directory '" ASSETS_SUBDIR "'\n"); + return 1; + } + if (!Align(256, fpRom, &address)) return false; if (!AppendAssets(fpRom, &address, &root, fatEntries)) return false; diff --git a/tools/rom/util.h b/tools/rom/util.h index 884b9970..a6d0e207 100644 --- a/tools/rom/util.h +++ b/tools/rom/util.h @@ -43,52 +43,19 @@ bool WcharToUtf8(wchar_t *in, size_t inSize, char *out, size_t outSize, size_t * #endif } -// typedef struct { -// #ifdef _WIN32 -// WIN32_FIND_DATA findData; -// HANDLE hFind; -// bool done; -// #elif __linux__ -// DIR *dir; -// struct dirent *entry; -// #endif -// } DirContext; - -// bool BeginDir(DirContext *ctx) { -// #ifdef _WIN32 -// ctx->hFind = FindFirstFileA("*", &ctx->findData); -// if (ctx->hFind == INVALID_HANDLE_VALUE) FATAL("Failed to begin walking directory\n"); -// return true; -// #elif __linux__ -// ctx->dir = opendir("."); -// if (ctx->dir == NULL) FATAL("Failed to begin walking directory\n"); -// ctx->entry = readdir(ctx->dir); -// return true; -// #endif -// } - -// bool NextFile(DirContext *ctx, char *pName, size_t nameSize, bool *pIsDir) { -// #ifdef _WIN32 -// if (ctx->done) return false; -// strncpy(pName, ctx->findData.cFileName, nameSize); -// *pIsDir = (ctx->findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; -// if (!FindNextFileA(ctx->hFind, &ctx->findData)) ctx->done = true; -// return true; -// #elif __linux__ -// if (ctx->entry == NULL) return false; -// strncpy(pName, ctx->entry.d_name, nameSize); -// *pIsDir = ctx->entry.d_type == DT_DIR; -// ctx->entry = readdir(ctx->dir); -// return true; -// #endif -// } - -// void EndDir(DirContext *ctx) { -// #ifdef _WIN32 -// FindClose(ctx->hFind); -// #elif __linux__ -// closedir(ctx->dir); -// #endif -// } +bool Utf8ToWchar(char *in, size_t inSize, wchar_t *out, size_t outSize) { +#ifdef _WIN32 + size_t resultSize = MultiByteToWideChar(CP_UTF8, 0, in, inSize, out, outSize / sizeof(wchar_t)); + if (resultSize == 0) FATAL("Failed to convert from UTF-8: %d\n", GetLastError()); + return true; +#elif __linux__ + iconv_t convDesc = iconv_open("UTF-8", "UTF-16"); + if (convDesc == -1) FATAL("Failed to get conversion description from UTF-8\n"); + size_t remainingBytes = outSize; + if (iconv(convDesc, &in, &inSize, &out, &remainingBytes) == -1) FATAL("Failed to convert from UTF-8\n"); + if (inSize > 0) FATAL("Some characters were not converted from UTF-8\n"); + return true; +#endif +} #endif