Append assets to ROM in predefined directory order

This commit is contained in:
Aetias
2023-10-27 19:26:23 +02:00
parent 8068345f57
commit 2b46dbee7f
4 changed files with 149 additions and 40 deletions
+34
View File
@@ -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/
/
+75 -36
View File
@@ -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);
+30 -4
View File
@@ -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
+10
View File
@@ -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