diff --git a/assets.txt b/assets.txt new file mode 100644 index 00000000..f6fea013 --- /dev/null +++ b/assets.txt @@ -0,0 +1,34 @@ +/Effect/ +/Environment/ +/Event/ +/Font/ +/Map/ +/Map2D/ +/MapObj/ +/MapUnit/ +/Menu/ +/Npc/ +/Other/ +/Player/ +/Ship/ +/SoundData/ +/Test/ +/Japanese/Menu/ +/Japanese/Message/ +/English/Menu/ +/English/Message/ +/German/Menu/ +/German/Message/ +/French/Menu/ +/French/Message/ +/Italian/Menu/ +/Italian/Message/ +/Spanish/Menu/ +/Spanish/Message/ +/Japanese/ +/English/ +/French/ +/German/ +/Italian/ +/Spanish/ +/ diff --git a/tools/rom/build.c b/tools/rom/build.c index cbefc6d8..0d9ac1a8 100644 --- a/tools/rom/build.c +++ b/tools/rom/build.c @@ -571,55 +571,83 @@ bool WriteBanner(FILE *fpRom, size_t *pAddress) { return true; } -bool AppendAssetFiles(FILE *fpRom, size_t *pAddress, const FileTree *tree, FatEntry *entries, size_t firstFileId) { +bool TraverseAndAppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *tree, FatEntry *entries, uint16_t firstFileId) { size_t address = *pAddress; + size_t fileId = firstFileId; - for (size_t i = 0; i < tree->numChildren; ++i, ++fileId) { - FileTree *child = &tree->children[i]; - FntSubEntry *entry = child->entry; - if (entry->isSubdir) continue; - char name[128]; - strncpy(name, entry->name, entry->length); - name[entry->length] = '\0'; - if (!Align(512, fpRom, &address)) return false; - size_t startOffset = address; - if (!AppendFile(fpRom, name, &address, NULL)) return false; - entries[fileId].startOffset = startOffset; - entries[fileId].endOffset = address; - } - *pAddress = address; - return true; -} - -bool TraverseAndAppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *tree, FatEntry *entries) { - size_t address = *pAddress; - - // Traverse directories for (size_t i = 0; i < tree->numChildren; ++i) { FileTree *child = &tree->children[i]; + if (child->addedToFat) continue; FntSubEntry *entry = child->entry; - if (!entry->isSubdir) continue; char name[128]; strncpy(name, entry->name, entry->length); name[entry->length] = '\0'; + if (!entry->isSubdir) { + if (!Align(512, fpRom, &address)) return false; + size_t startOffset = address; + if (!AppendFile(fpRom, name, &address, NULL)) return false; + entries[fileId].startOffset = startOffset; + entries[fileId].endOffset = address; + ++fileId; + continue; + } if (chdir(name) != 0) FATAL("Failed to enter assets directory '%s'\n", name); - if (!TraverseAndAppendAssets(fpRom, &address, child, entries)) return false; + if (!TraverseAndAppendAssets(fpRom, &address, child, entries, child->firstFileId)) return false; if (chdir("..") != 0) FATAL("Failed to leave assets directory '%s'\n", name); } - if (tree->entry != NULL) { // Directory is not root - AppendAssetFiles(fpRom, &address, tree, entries, tree->firstFileId); - } - *pAddress = address; return true; } -bool AppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *root, FatEntry *entries, size_t numOverlays) { +bool AppendAssets( + FILE *fpRom, + size_t *pAddress, + FileTree *root, + FatEntry *entries, + size_t numOverlays, + const char *assetsListFile +) { size_t address = *pAddress; - if (!TraverseAndAppendAssets(fpRom, &address, root, entries)) return false; - if (!AppendAssetFiles(fpRom, &address, root, entries, numOverlays)) return false; + if (assetsListFile == NULL) { + if (!TraverseAndAppendAssets(fpRom, &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); + 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); + assetsList[listSize] = '\0'; + + char assetsDir[256]; + if (getcwd(assetsDir, sizeof(assetsDir)) == NULL) 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' && chdir(&path[1]) != 0) FATAL("Failed to enter assets directory '%s'\n", path); + if (!TraverseAndAppendAssets(fpRom, &address, subTree, entries, firstFileId)) return false; + if (chdir(assetsDir) != 0) FATAL("Failed to leave assets directory '%s'\n", path); + + subTree->addedToFat = true; + } + + free(assetsList); *pAddress = address; return true; @@ -695,17 +723,18 @@ void PrintUsage(const char *program) { printf( "buildrom " VERSION "\n" "\n" - "Usage: %s -a BASEDIR -b BUILDDIR -r REGION -o OUTFILE [-7 ARM7BIOS]\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", + " -7 ARM7BIOS\tPath to ARM7 BIOS file\n" + " -s ASSETS \tPath to assets list\n", program ); } -int main(int argc, const char **argv) { +int main(int argc, char **argv) { // --------------------- Parse command line arguments --------------------- const char *program = argv[0]; @@ -717,6 +746,7 @@ int main(int argc, const char **argv) { 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) { @@ -743,6 +773,12 @@ int main(int argc, const char **argv) { 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"); @@ -818,6 +854,7 @@ int main(int argc, const char **argv) { // --------------------- Get canonical file paths --------------------- + if (assetsListFile != NULL && !AllocFullPath(assetsListFile, &assetsListFile)) return 1; if (chdir(baseDir) != 0) { fprintf(stderr, "Failed to enter base directory '%s'\n", baseDir); return 1; @@ -875,7 +912,7 @@ int main(int argc, const char **argv) { // --------------------- Write file name table (FNT) --------------------- FileTree root; if (!MakeFileTree(&root)) return false; - if (!SortFileTree(&root)) return false; + if (!SortFileTree(&root, CompareFileTreeNormal)) return false; if (!Align(512, fpRom, &address)) return 1; size_t numFiles = 0; @@ -911,7 +948,9 @@ int main(int argc, const char **argv) { // --------------------- Write assets --------------------- if (!Align(512, fpRom, &address)) return false; - if (!AppendAssets(fpRom, &address, &root, fatEntries, numOverlays)) return false; + if (!SortFileTree(&root, CompareFileTreeAscii)) return false; + if (!AppendAssets(fpRom, &address, &root, fatEntries, numOverlays, assetsListFile)) return false; + if (assetsListFile != NULL) FreeFullPath(&assetsListFile); if (!RewriteFat(fpRom, header.fileAllocs.offset, fatEntries, numFiles)) free(fatEntries); diff --git a/tools/rom/files.h b/tools/rom/files.h index 7af4cbdc..3869e87e 100644 --- a/tools/rom/files.h +++ b/tools/rom/files.h @@ -9,6 +9,7 @@ typedef struct FileTree { uint16_t numChildren; uint16_t maxChildren; uint16_t firstFileId; + bool addedToFat; FntSubEntry *entry; } FileTree; @@ -96,6 +97,7 @@ bool _FileTreeFileCallback(const char *name, bool isDir, void *userData) { 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)); @@ -109,6 +111,7 @@ bool MakeFileTree(FileTree *pTree) { tree.children = NULL; tree.numChildren = 0; tree.maxChildren = 0; + tree.addedToFat = false; if (!_GrowFileTreeChildren(&tree, 64)) return false; tree.entry = NULL; @@ -127,6 +130,7 @@ bool FreeFileTree(FileTree *pTree) { } pTree->numChildren = 0; pTree->maxChildren = 0; + pTree->addedToFat = false; if (pTree->entry != NULL) { free(pTree->entry); pTree->entry = NULL; @@ -134,7 +138,7 @@ bool FreeFileTree(FileTree *pTree) { return true; } -int CompareFileTree(const void *a, const void *b) { +int CompareFileTreeNormal(const void *a, const void *b) { FileTree *treeA = (FileTree*) a; FileTree *treeB = (FileTree*) b; @@ -163,18 +167,40 @@ int CompareFileTree(const void *a, const void *b) { return 0; } -bool SortFileTree(FileTree *pTree) { +int CompareFileTreeAscii(const void *a, const void *b) { + FileTree *treeA = (FileTree*) a; + FileTree *treeB = (FileTree*) b; + return strcmp(treeA->entry->name, treeB->entry->name); +} + +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), CompareFileTree); + qsort(tree.children, tree.numChildren, sizeof(*tree.children), compare); for (size_t i = 0; i < tree.numChildren; ++i) { - if (!SortFileTree(&tree.children[i])) return false; + 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/util.h b/tools/rom/util.h index e245b3b2..29c2e157 100644 --- a/tools/rom/util.h +++ b/tools/rom/util.h @@ -85,4 +85,14 @@ void FreeFullPath(char **pFullPath) { *pFullPath = NULL; } +char* SplitLine(char *str) { + while (*str != '\n' && *str != '\r') { + if (*str == '\0') return str; + ++str; + } + *str++ = '\0'; + while (*str == '\n' || *str == '\r') ++str; + return str; +} + #endif