mirror of
https://github.com/zeldaret/ph
synced 2026-06-07 11:57:43 -04:00
Convert indentation to spaces
This commit is contained in:
+325
-323
@@ -114,235 +114,235 @@ void InitHeader(Header *pHeader, const BuildInfo *info) {
|
||||
}
|
||||
|
||||
bool AppendFile(FILE *fpRom, const char *filePath, size_t *pAddress, uint32_t *pFileSize) {
|
||||
assert(readBuffer != NULL);
|
||||
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);
|
||||
|
||||
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);
|
||||
bytesWritten += bytesRead;
|
||||
}
|
||||
fclose(fp);
|
||||
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);
|
||||
|
||||
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);
|
||||
bytesWritten += bytesRead;
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
*pAddress += size;
|
||||
if (pFileSize != NULL) *pFileSize = size;
|
||||
return true;
|
||||
*pAddress += size;
|
||||
if (pFileSize != NULL) *pFileSize = size;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Align(size_t alignment, FILE *fpRom, size_t *pAddress) {
|
||||
assert((alignment & (alignment - 1)) == 0);
|
||||
assert((alignment & (alignment - 1)) == 0);
|
||||
|
||||
size_t mask = alignment - 1;
|
||||
size_t address = ftell(fpRom);
|
||||
size_t nextAddr = (address + mask) & ~mask;
|
||||
while (address < nextAddr) {
|
||||
if (fputc(0xff, fpRom) == -1) FATAL("Failed to pad output ROM at address 0x%x\n", address);
|
||||
address += 1;
|
||||
}
|
||||
size_t mask = alignment - 1;
|
||||
size_t address = ftell(fpRom);
|
||||
size_t nextAddr = (address + mask) & ~mask;
|
||||
while (address < nextAddr) {
|
||||
if (fputc(0xff, fpRom) == -1) FATAL("Failed to pad output ROM at address 0x%x\n", address);
|
||||
address += 1;
|
||||
}
|
||||
*pAddress = address;
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteArm9Overlays(FILE *fpRom, size_t *pAddress, size_t *pNumOverlays, FatEntry *entries, size_t maxEntries) {
|
||||
size_t address = *pAddress;
|
||||
uint32_t ovNum = 0;
|
||||
char fileName[32];
|
||||
size_t address = *pAddress;
|
||||
uint32_t ovNum = 0;
|
||||
char fileName[32];
|
||||
|
||||
if (chdir(OVERLAYS_SUBDIR) != 0) FATAL("Failed to enter overlays directory '" OVERLAYS_SUBDIR "'\n");
|
||||
if (chdir(OVERLAYS_SUBDIR) != 0) FATAL("Failed to enter overlays directory '" OVERLAYS_SUBDIR "'\n");
|
||||
|
||||
while (true) {
|
||||
sprintf(fileName, "ov%02d.lz", ovNum);
|
||||
if (!Align(512, fpRom, &address)) return false;
|
||||
size_t startOffset = address;
|
||||
if (!AppendFile(fpRom, fileName, &address, NULL)) break;
|
||||
entries[ovNum].startOffset = startOffset;
|
||||
entries[ovNum].endOffset = address;
|
||||
while (true) {
|
||||
sprintf(fileName, "ov%02d.lz", ovNum);
|
||||
if (!Align(512, fpRom, &address)) return false;
|
||||
size_t startOffset = address;
|
||||
if (!AppendFile(fpRom, fileName, &address, NULL)) break;
|
||||
entries[ovNum].startOffset = startOffset;
|
||||
entries[ovNum].endOffset = address;
|
||||
ovNum += 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (chdir("..") != 0) FATAL("Failed to leave overlays directory '" OVERLAYS_SUBDIR "'\n");
|
||||
if (chdir("..") != 0) FATAL("Failed to leave overlays directory '" OVERLAYS_SUBDIR "'\n");
|
||||
|
||||
*pAddress = address;
|
||||
*pNumOverlays = ovNum;
|
||||
return true;
|
||||
*pAddress = address;
|
||||
*pNumOverlays = ovNum;
|
||||
return true;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
FntEntry *table;
|
||||
uint16_t tableSize;
|
||||
uint16_t tableMax;
|
||||
FntEntry *table;
|
||||
uint16_t tableSize;
|
||||
uint16_t tableMax;
|
||||
|
||||
uint16_t nextFileId;
|
||||
uint16_t parentId;
|
||||
uint16_t nextFileId;
|
||||
uint16_t parentId;
|
||||
|
||||
uint8_t *subtable;
|
||||
size_t subtableSize;
|
||||
size_t subtableMax;
|
||||
uint8_t *subtable;
|
||||
size_t subtableSize;
|
||||
size_t subtableMax;
|
||||
} FntContext;
|
||||
|
||||
bool GrowFntTable(FntContext *pContext, size_t minEntries) {
|
||||
FntContext ctx;
|
||||
memcpy(&ctx, pContext, sizeof(ctx));
|
||||
FntContext ctx;
|
||||
memcpy(&ctx, pContext, sizeof(ctx));
|
||||
|
||||
if (minEntries <= ctx.tableMax) return true;
|
||||
while (minEntries > ctx.tableMax) {
|
||||
ctx.tableMax *= 2;
|
||||
}
|
||||
if (minEntries <= ctx.tableMax) return true;
|
||||
while (minEntries > ctx.tableMax) {
|
||||
ctx.tableMax *= 2;
|
||||
}
|
||||
|
||||
FntEntry *newTable = realloc(ctx.table, ctx.tableMax * sizeof(FntEntry));
|
||||
if (newTable == NULL) FATAL("Failed to reallocate FNT table to %d entries\n", ctx.tableMax);
|
||||
ctx.table = newTable;
|
||||
FntEntry *newTable = realloc(ctx.table, ctx.tableMax * sizeof(FntEntry));
|
||||
if (newTable == NULL) FATAL("Failed to reallocate FNT table to %d entries\n", ctx.tableMax);
|
||||
ctx.table = newTable;
|
||||
|
||||
memcpy(pContext, &ctx, sizeof(ctx));
|
||||
return true;
|
||||
memcpy(pContext, &ctx, sizeof(ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GrowFntSubtable(FntContext *pContext, size_t growSize) {
|
||||
FntContext ctx;
|
||||
memcpy(&ctx, pContext, sizeof(ctx));
|
||||
FntContext ctx;
|
||||
memcpy(&ctx, pContext, sizeof(ctx));
|
||||
|
||||
if (ctx.subtableSize + growSize < ctx.subtableMax) return true;
|
||||
while (ctx.subtableSize + growSize >= ctx.subtableMax) {
|
||||
ctx.subtableMax *= 2;
|
||||
}
|
||||
if (ctx.subtableSize + growSize < ctx.subtableMax) return true;
|
||||
while (ctx.subtableSize + growSize >= ctx.subtableMax) {
|
||||
ctx.subtableMax *= 2;
|
||||
}
|
||||
|
||||
uint8_t *newTable = realloc(ctx.subtable, ctx.subtableMax);
|
||||
if (newTable == NULL) FATAL("Failed to reallocate FNT subtable to %d bytes\n", ctx.subtableMax);
|
||||
ctx.subtable = newTable;
|
||||
uint8_t *newTable = realloc(ctx.subtable, ctx.subtableMax);
|
||||
if (newTable == NULL) FATAL("Failed to reallocate FNT subtable to %d bytes\n", ctx.subtableMax);
|
||||
ctx.subtable = newTable;
|
||||
|
||||
memcpy(pContext, &ctx, sizeof(ctx));
|
||||
return true;
|
||||
memcpy(pContext, &ctx, sizeof(ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteFntSubtable(FileTree *tree, FntContext *pContext) {
|
||||
FntContext ctx;
|
||||
memcpy(&ctx, pContext, sizeof(ctx));
|
||||
size_t subtableStart = ctx.subtableSize;
|
||||
FntContext ctx;
|
||||
memcpy(&ctx, pContext, sizeof(ctx));
|
||||
size_t subtableStart = ctx.subtableSize;
|
||||
|
||||
// Create initial subtable entries
|
||||
size_t numFiles = 0;
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
FileTree *child = &tree->children[i];
|
||||
FntSubEntry *entry = child->entry;
|
||||
if (!entry->isSubdir) numFiles += 1;
|
||||
// Create initial subtable entries
|
||||
size_t numFiles = 0;
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
FileTree *child = &tree->children[i];
|
||||
FntSubEntry *entry = child->entry;
|
||||
if (!entry->isSubdir) numFiles += 1;
|
||||
|
||||
size_t entrySize = sizeof(*entry) + entry->length + (entry->isSubdir ? 2 : 0);
|
||||
if (!GrowFntSubtable(&ctx, entrySize)) return false;
|
||||
size_t entrySize = sizeof(*entry) + entry->length + (entry->isSubdir ? 2 : 0);
|
||||
if (!GrowFntSubtable(&ctx, entrySize)) return false;
|
||||
|
||||
FntSubEntry *dest = (FntSubEntry*) (ctx.subtable + ctx.subtableSize);
|
||||
memcpy(dest, entry, entrySize);
|
||||
ctx.subtableSize += entrySize;
|
||||
}
|
||||
FntSubEntry *dest = (FntSubEntry*) (ctx.subtable + ctx.subtableSize);
|
||||
memcpy(dest, entry, entrySize);
|
||||
ctx.subtableSize += entrySize;
|
||||
}
|
||||
|
||||
if (!GrowFntSubtable(&ctx, 1)) return false;
|
||||
ctx.subtable[ctx.subtableSize] = 0; // End of subtable
|
||||
ctx.subtableSize += 1;
|
||||
if (!GrowFntSubtable(&ctx, 1)) return false;
|
||||
ctx.subtable[ctx.subtableSize] = 0; // End of subtable
|
||||
ctx.subtableSize += 1;
|
||||
|
||||
ctx.nextFileId += numFiles;
|
||||
|
||||
// Recurse child directories
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
FileTree *child = &tree->children[i];
|
||||
FntSubEntry *entry = child->entry;
|
||||
if (!entry->isSubdir) continue;
|
||||
uint16_t subdirId = 0xf000 | ctx.tableSize;
|
||||
WRITE_SUBDIR_ID(entry, subdirId);
|
||||
child->firstFileId = ctx.nextFileId;
|
||||
FntEntry mainEntry;
|
||||
mainEntry.subtableOffset = ctx.subtableSize; // will add main table length later
|
||||
mainEntry.firstFile = ctx.nextFileId;
|
||||
mainEntry.parentId = ctx.parentId;
|
||||
if (!GrowFntTable(&ctx, ctx.tableSize + 1)) return false;
|
||||
memcpy(&ctx.table[ctx.tableSize], &mainEntry, sizeof(mainEntry));
|
||||
// Recurse child directories
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
FileTree *child = &tree->children[i];
|
||||
FntSubEntry *entry = child->entry;
|
||||
if (!entry->isSubdir) continue;
|
||||
uint16_t subdirId = 0xf000 | ctx.tableSize;
|
||||
WRITE_SUBDIR_ID(entry, subdirId);
|
||||
child->firstFileId = ctx.nextFileId;
|
||||
FntEntry mainEntry;
|
||||
mainEntry.subtableOffset = ctx.subtableSize; // will add main table length later
|
||||
mainEntry.firstFile = ctx.nextFileId;
|
||||
mainEntry.parentId = ctx.parentId;
|
||||
if (!GrowFntTable(&ctx, ctx.tableSize + 1)) return false;
|
||||
memcpy(&ctx.table[ctx.tableSize], &mainEntry, sizeof(mainEntry));
|
||||
ctx.tableSize += 1;
|
||||
|
||||
uint16_t oldParentId = ctx.parentId;
|
||||
ctx.parentId = subdirId;
|
||||
uint16_t oldParentId = ctx.parentId;
|
||||
ctx.parentId = subdirId;
|
||||
|
||||
char name[128];
|
||||
strncpy(name, entry->name, entry->length);
|
||||
char name[128];
|
||||
strncpy(name, entry->name, entry->length);
|
||||
name[entry->length] = '\0';
|
||||
if (!WriteFntSubtable(child, &ctx)) return false;
|
||||
if (!WriteFntSubtable(child, &ctx)) return false;
|
||||
|
||||
ctx.parentId = oldParentId;
|
||||
}
|
||||
ctx.parentId = oldParentId;
|
||||
}
|
||||
|
||||
// Update subdir IDs
|
||||
size_t subtableOffset = 0;
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
FileTree *child = &tree->children[i];
|
||||
FntSubEntry *entry = child->entry;
|
||||
size_t entrySize = sizeof(*entry) + entry->length + (entry->isSubdir ? 2 : 0);
|
||||
memcpy(ctx.subtable + subtableStart + subtableOffset, entry, entrySize);
|
||||
subtableOffset += entrySize;
|
||||
}
|
||||
|
||||
memcpy(pContext, &ctx, sizeof(ctx));
|
||||
return true;
|
||||
// Update subdir IDs
|
||||
size_t subtableOffset = 0;
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
FileTree *child = &tree->children[i];
|
||||
FntSubEntry *entry = child->entry;
|
||||
size_t entrySize = sizeof(*entry) + entry->length + (entry->isSubdir ? 2 : 0);
|
||||
memcpy(ctx.subtable + subtableStart + subtableOffset, entry, entrySize);
|
||||
subtableOffset += entrySize;
|
||||
}
|
||||
|
||||
memcpy(pContext, &ctx, sizeof(ctx));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteFnt(FILE *fpRom, size_t *pAddress, FileTree *pRoot, size_t firstFileId, size_t *pNumFiles) {
|
||||
size_t address = *pAddress;
|
||||
size_t address = *pAddress;
|
||||
|
||||
FntContext ctx;
|
||||
ctx.table = malloc(INITIAL_TABLE_SIZE * sizeof(FntEntry));
|
||||
if (ctx.table == NULL) FATAL("Failed to allocate FNT table\n");
|
||||
ctx.tableSize = 1;
|
||||
ctx.tableMax = INITIAL_TABLE_SIZE;
|
||||
FntContext ctx;
|
||||
ctx.table = malloc(INITIAL_TABLE_SIZE * sizeof(FntEntry));
|
||||
if (ctx.table == NULL) FATAL("Failed to allocate FNT table\n");
|
||||
ctx.tableSize = 1;
|
||||
ctx.tableMax = INITIAL_TABLE_SIZE;
|
||||
|
||||
ctx.nextFileId = firstFileId;
|
||||
ctx.parentId = 0xf000; // root directory
|
||||
ctx.nextFileId = firstFileId;
|
||||
ctx.parentId = 0xf000; // root directory
|
||||
|
||||
ctx.subtable = malloc(INITIAL_SUBTABLE_SIZE);
|
||||
if (ctx.subtable == NULL) FATAL("Failed to allocate FNT subtable\n");
|
||||
ctx.subtableSize = 0;
|
||||
ctx.subtableMax = INITIAL_SUBTABLE_SIZE;
|
||||
ctx.subtable = malloc(INITIAL_SUBTABLE_SIZE);
|
||||
if (ctx.subtable == NULL) FATAL("Failed to allocate FNT subtable\n");
|
||||
ctx.subtableSize = 0;
|
||||
ctx.subtableMax = INITIAL_SUBTABLE_SIZE;
|
||||
|
||||
ctx.table[0].subtableOffset = 0; // will add main table length later
|
||||
ctx.table[0].firstFile = firstFileId;
|
||||
ctx.table[0].parentId = 0; // will be set to number of directories later
|
||||
ctx.table[0].firstFile = firstFileId;
|
||||
ctx.table[0].parentId = 0; // will be set to number of directories later
|
||||
|
||||
size_t tableStart = address;
|
||||
if (!WriteFntSubtable(pRoot, &ctx)) return false;
|
||||
size_t tableStart = address;
|
||||
if (!WriteFntSubtable(pRoot, &ctx)) return false;
|
||||
|
||||
size_t tableLength = ctx.tableSize * sizeof(FntEntry);
|
||||
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");
|
||||
address += ctx.tableSize * sizeof(FntEntry);
|
||||
if (fwrite(ctx.subtable, ctx.subtableSize, 1, fpRom) != 1) FATAL("Failed to write FNT subtables\n");
|
||||
address += ctx.subtableSize;
|
||||
size_t tableLength = ctx.tableSize * sizeof(FntEntry);
|
||||
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");
|
||||
address += ctx.tableSize * sizeof(FntEntry);
|
||||
if (fwrite(ctx.subtable, ctx.subtableSize, 1, fpRom) != 1) FATAL("Failed to write FNT subtables\n");
|
||||
address += ctx.subtableSize;
|
||||
|
||||
free(ctx.table);
|
||||
free(ctx.subtable);
|
||||
free(ctx.table);
|
||||
free(ctx.subtable);
|
||||
|
||||
*pAddress = address;
|
||||
*pNumFiles = ctx.nextFileId;
|
||||
return true;
|
||||
*pAddress = address;
|
||||
*pNumFiles = ctx.nextFileId;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WriteFat(FILE *fpRom, size_t *pAddress, size_t numFiles) {
|
||||
size_t address = *pAddress;
|
||||
size_t fatStart = address;
|
||||
size_t address = *pAddress;
|
||||
size_t fatStart = address;
|
||||
|
||||
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");
|
||||
}
|
||||
address += sizeof(blank) * numFiles;
|
||||
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");
|
||||
}
|
||||
address += sizeof(blank) * numFiles;
|
||||
|
||||
*pAddress = address;
|
||||
return true;
|
||||
*pAddress = address;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ReadTitle(const char *language, const char *file, wchar_t *title, size_t titleSize) {
|
||||
@@ -402,45 +402,45 @@ bool WriteBanner(FILE *fpRom, size_t *pAddress) {
|
||||
}
|
||||
|
||||
bool AppendAssets(FILE *fpRom, size_t *pAddress, const FileTree *tree, FatEntry *entries) {
|
||||
size_t address = *pAddress;
|
||||
size_t address = *pAddress;
|
||||
|
||||
// Traverse directories
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
FileTree *child = &tree->children[i];
|
||||
FntSubEntry *entry = child->entry;
|
||||
if (!entry->isSubdir) continue;
|
||||
char name[128];
|
||||
strncpy(name, entry->name, entry->length);
|
||||
// Traverse directories
|
||||
for (size_t i = 0; i < tree->numChildren; ++i) {
|
||||
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 (chdir(name) != 0) FATAL("Failed to enter assets directory '%s'\n", name);
|
||||
if (!AppendAssets(fpRom, &address, child, entries)) return false;
|
||||
if (chdir("..") != 0) FATAL("Failed to leave assets directory '%s'\n", name);
|
||||
}
|
||||
|
||||
// Append files
|
||||
size_t fileId = tree->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);
|
||||
if (chdir(name) != 0) FATAL("Failed to enter assets directory '%s'\n", name);
|
||||
if (!AppendAssets(fpRom, &address, child, entries)) return false;
|
||||
if (chdir("..") != 0) FATAL("Failed to leave assets directory '%s'\n", name);
|
||||
}
|
||||
|
||||
// Append files
|
||||
size_t fileId = tree->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;
|
||||
}
|
||||
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;
|
||||
*pAddress = address;
|
||||
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);
|
||||
if (fwrite(entries, sizeof(*entries), numFiles, fpRom) != numFiles) FATAL("Failed to rewrite FAT table\n");
|
||||
fseek(fpRom, 0, SEEK_END);
|
||||
}
|
||||
|
||||
void PrintUsage(const char *program) {
|
||||
@@ -450,7 +450,7 @@ void PrintUsage(const char *program) {
|
||||
"Usage: %s -a BASEDIR -b BUILDDIR -r REGION -o OUTFILE\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"
|
||||
" -r REGION \tJ = Japan, E = USA, P = Europe\n"
|
||||
" -o OUTFILE \tOutput ROM file\n",
|
||||
program
|
||||
);
|
||||
@@ -465,7 +465,7 @@ int main(int argc, const char **argv) {
|
||||
const char *baseDir = NULL;
|
||||
const char *buildDir = NULL;
|
||||
const char *romFile = NULL;
|
||||
Region region = 0;
|
||||
Region region = 0;
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (strcmp(argv[i], "-o") == 0) {
|
||||
if (++i >= argc) {
|
||||
@@ -486,171 +486,173 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
buildDir = argv[i];
|
||||
} else if (strcmp(argv[i], "-r") == 0) {
|
||||
if (++i >= argc) {
|
||||
fprintf(stderr, "Expected region after -r\n");
|
||||
return 1;
|
||||
}
|
||||
if (strlen(argv[i]) != 1) {
|
||||
fprintf(stderr, "Region must be a single character\n");
|
||||
return 1;
|
||||
}
|
||||
region = argv[i][0];
|
||||
} else {
|
||||
if (++i >= argc) {
|
||||
fprintf(stderr, "Expected region after -r\n");
|
||||
return 1;
|
||||
}
|
||||
if (strlen(argv[i]) != 1) {
|
||||
fprintf(stderr, "Region must be a single character\n");
|
||||
return 1;
|
||||
}
|
||||
region = argv[i][0];
|
||||
} else {
|
||||
fprintf(stderr, "Unknown option '%s'\n", argv[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if (baseDir == NULL) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Please provide a base directory, see usage above\n");
|
||||
return 1;
|
||||
}
|
||||
if (buildDir == NULL) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Please provide a build directory, see usage above\n");
|
||||
return 1;
|
||||
}
|
||||
if (region != REGION_JAPAN && region != REGION_USA && region != REGION_EUROPE) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Invalid region '%c', see usage above\n", region);
|
||||
return 1;
|
||||
}
|
||||
if (romFile == NULL) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Please provide an output ROM file, see usage above\n");
|
||||
return 1;
|
||||
}
|
||||
if (baseDir == NULL) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Please provide a base directory, see usage above\n");
|
||||
return 1;
|
||||
}
|
||||
if (buildDir == NULL) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Please provide a build directory, see usage above\n");
|
||||
return 1;
|
||||
}
|
||||
if (region != REGION_JAPAN && region != REGION_USA && region != REGION_EUROPE) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Invalid region '%c', see usage above\n", region);
|
||||
return 1;
|
||||
}
|
||||
if (romFile == NULL) {
|
||||
PrintUsage(program);
|
||||
fprintf(stderr, "Please provide an output ROM file, see usage above\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
char rootDir[256];
|
||||
if (getcwd(rootDir, sizeof(rootDir)) == NULL) {
|
||||
fprintf(stderr, "Failed to get root directory\n");
|
||||
return 1;
|
||||
}
|
||||
char rootDir[256];
|
||||
if (getcwd(rootDir, sizeof(rootDir)) == NULL) {
|
||||
fprintf(stderr, "Failed to get root directory\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *fpRom = fopen(romFile, "wb");
|
||||
if (fpRom == NULL) {
|
||||
fprintf(stderr, "Failed to open output ROM file '%s'\n", romFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
readBuffer = malloc(BUFFER_SIZE);
|
||||
if (readBuffer == NULL) {
|
||||
fprintf(stderr, "Failed to allocate read buffer to %d bytes\n", BUFFER_SIZE);
|
||||
return 1;
|
||||
}
|
||||
FILE *fpRom = fopen(romFile, "wb");
|
||||
if (fpRom == NULL) {
|
||||
fprintf(stderr, "Failed to open output ROM file '%s'\n", romFile);
|
||||
return 1;
|
||||
}
|
||||
|
||||
readBuffer = malloc(BUFFER_SIZE);
|
||||
if (readBuffer == NULL) {
|
||||
fprintf(stderr, "Failed to allocate read buffer to %d bytes\n", BUFFER_SIZE);
|
||||
return 1;
|
||||
}
|
||||
|
||||
GenerateCrcTable();
|
||||
|
||||
BuildInfo info;
|
||||
info.region = region;
|
||||
size_t address = 0;
|
||||
BuildInfo info;
|
||||
info.region = region;
|
||||
size_t address = 0;
|
||||
|
||||
Header header;
|
||||
InitHeader(&header, &info);
|
||||
Header header;
|
||||
InitHeader(&header, &info);
|
||||
|
||||
if (fwrite(&header, sizeof(header), 1, fpRom) != 1) {
|
||||
fprintf(stderr, "Failed to write NDS header\n");
|
||||
return 1;
|
||||
}
|
||||
address += sizeof(header);
|
||||
if (fwrite(&header, sizeof(header), 1, fpRom) != 1) {
|
||||
fprintf(stderr, "Failed to write NDS header\n");
|
||||
return 1;
|
||||
}
|
||||
address += sizeof(header);
|
||||
|
||||
if (chdir(buildDir) != 0) {
|
||||
fprintf(stderr, "Failed to enter build directory '%s'\n", buildDir);
|
||||
return 1;
|
||||
}
|
||||
if (chdir(buildDir) != 0) {
|
||||
fprintf(stderr, "Failed to enter build directory '%s'\n", buildDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.arm9.offset = address;
|
||||
if (!AppendFile(fpRom, ARM9_PROGRAM_FILE, &address, &header.arm9.size)) return 1;
|
||||
if (!AppendFile(fpRom, ARM9_FOOTER_FILE, &address, NULL)) return 1;
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.arm9.offset = address;
|
||||
if (!AppendFile(fpRom, ARM9_PROGRAM_FILE, &address, &header.arm9.size)) return 1;
|
||||
if (!AppendFile(fpRom, ARM9_FOOTER_FILE, &address, NULL)) return 1;
|
||||
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.arm9Overlays.offset = address;
|
||||
if (!AppendFile(fpRom, ARM9_OVERLAY_TABLE_FILE, &address, &header.arm9Overlays.size)) return 1;
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.arm9Overlays.offset = address;
|
||||
if (!AppendFile(fpRom, ARM9_OVERLAY_TABLE_FILE, &address, &header.arm9Overlays.size)) return 1;
|
||||
|
||||
FatEntry overlayEntries[MAX_OVERLAYS];
|
||||
size_t numOverlays = 0;
|
||||
if (!WriteArm9Overlays(fpRom, &address, &numOverlays, overlayEntries, MAX_OVERLAYS)) return 1;
|
||||
FatEntry overlayEntries[MAX_OVERLAYS];
|
||||
size_t numOverlays = 0;
|
||||
if (!WriteArm9Overlays(fpRom, &address, &numOverlays, overlayEntries, MAX_OVERLAYS)) return 1;
|
||||
|
||||
if (chdir(rootDir) != 0) {
|
||||
fprintf(stderr, "Failed to leave build directory '%s'\n", buildDir);
|
||||
return 1;
|
||||
}
|
||||
if (chdir(rootDir) != 0) {
|
||||
fprintf(stderr, "Failed to leave build directory '%s'\n", buildDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chdir(baseDir) != 0) {
|
||||
fprintf(stderr, "Failed to enter base directory '%s'\n", baseDir);
|
||||
return 1;
|
||||
}
|
||||
if (chdir(baseDir) != 0) {
|
||||
fprintf(stderr, "Failed to enter base directory '%s'\n", baseDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.arm7.offset = address;
|
||||
if (!AppendFile(fpRom, ARM7_PROGRAM_FILE, &address, &header.arm7.size)) return 1;
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.arm7.offset = address;
|
||||
if (!AppendFile(fpRom, ARM7_PROGRAM_FILE, &address, &header.arm7.size)) return 1;
|
||||
|
||||
if (chdir(ASSETS_SUBDIR) != 0) {
|
||||
fprintf(stderr, "Failed to enter assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
if (chdir(ASSETS_SUBDIR) != 0) {
|
||||
fprintf(stderr, "Failed to enter assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
FileTree root;
|
||||
if (!MakeFileTree(&root)) return false;
|
||||
if (!SortFileTree(&root)) return false;
|
||||
FileTree root;
|
||||
if (!MakeFileTree(&root)) return false;
|
||||
if (!SortFileTree(&root)) return false;
|
||||
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
size_t numFiles = 0;
|
||||
header.fileNames.offset = address;
|
||||
if (!WriteFnt(fpRom, &address, &root, numOverlays, &numFiles)) return 1;
|
||||
header.fileNames.size = address - header.fileNames.offset;
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
size_t numFiles = 0;
|
||||
header.fileNames.offset = address;
|
||||
if (!WriteFnt(fpRom, &address, &root, numOverlays, &numFiles)) return 1;
|
||||
header.fileNames.size = address - header.fileNames.offset;
|
||||
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.fileAllocs.offset = address;
|
||||
if (!WriteFat(fpRom, &address, numFiles)) return 1;
|
||||
header.fileAllocs.size = address - header.fileAllocs.offset;
|
||||
if (!Align(512, fpRom, &address)) return 1;
|
||||
header.fileAllocs.offset = address;
|
||||
if (!WriteFat(fpRom, &address, numFiles)) return 1;
|
||||
header.fileAllocs.size = address - header.fileAllocs.offset;
|
||||
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 (chdir("..") != 0) {
|
||||
fprintf(stderr, "Failed to leave assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Align(512, 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 (chdir(ASSETS_SUBDIR) != 0) {
|
||||
fprintf(stderr, "Failed to enter assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!Align(512, fpRom, &address)) return false;
|
||||
if (!AppendAssets(fpRom, &address, &root, fatEntries)) return false;
|
||||
if (!Align(512, fpRom, &address)) return false;
|
||||
if (!AppendAssets(fpRom, &address, &root, fatEntries)) return false;
|
||||
|
||||
if (!RewriteFat(fpRom, header.fileAllocs.offset, fatEntries, numFiles))
|
||||
free(fatEntries);
|
||||
|
||||
if (!FreeFileTree(&root)) return false;
|
||||
if (!FreeFileTree(&root)) return false;
|
||||
|
||||
if (chdir("..") != 0) {
|
||||
fprintf(stderr, "Failed to leave assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
if (chdir("..") != 0) {
|
||||
fprintf(stderr, "Failed to leave assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chdir(rootDir) != 0) {
|
||||
fprintf(stderr, "Failed to leave base directory '%s'\n", baseDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chdir(rootDir) != 0) {
|
||||
fprintf(stderr, "Failed to leave base directory '%s'\n", baseDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
header.romSize = address;
|
||||
header.capacity = 15 - __builtin_clz(header.romSize);
|
||||
size_t romEnd = 1 << (17 + header.capacity);
|
||||
if (!Align(romEnd, fpRom, &address)) return 1;
|
||||
size_t romEnd = 1 << (17 + header.capacity);
|
||||
if (!Align(romEnd, fpRom, &address)) return 1;
|
||||
|
||||
fseek(fpRom, 0, SEEK_SET);
|
||||
if (fwrite(&header, sizeof(header), 1, fpRom) != 1) {
|
||||
fprintf(stderr, "Failed to rewrite header\n");
|
||||
return 1;
|
||||
}
|
||||
header.headerCrc = Crc(&header, offsetof(Header, headerCrc));
|
||||
|
||||
free(readBuffer);
|
||||
fclose(fpRom);
|
||||
fseek(fpRom, 0, SEEK_SET);
|
||||
if (fwrite(&header, sizeof(header), 1, fpRom) != 1) {
|
||||
fprintf(stderr, "Failed to rewrite header\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(readBuffer);
|
||||
fclose(fpRom);
|
||||
}
|
||||
|
||||
+115
-115
@@ -11,123 +11,123 @@
|
||||
#define VERSION "1.0"
|
||||
|
||||
bool MakeDir(const char *dir) {
|
||||
struct stat dirStat;
|
||||
if (stat(dir, &dirStat) != 0) {
|
||||
if (mkdir(dir, 0777) != 0) FATAL("Failed to make directory '%s'\n", dir);
|
||||
return true;
|
||||
}
|
||||
if (!S_ISDIR(dirStat.st_mode)) FATAL("Could not make directory '%s' due to a file with the same name\n");
|
||||
return true;
|
||||
struct stat dirStat;
|
||||
if (stat(dir, &dirStat) != 0) {
|
||||
if (mkdir(dir, 0777) != 0) FATAL("Failed to make directory '%s'\n", dir);
|
||||
return true;
|
||||
}
|
||||
if (!S_ISDIR(dirStat.st_mode)) FATAL("Could not make directory '%s' due to a file with the same name\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CheckRegion(const Header *pHeader, BuildInfo *pInfo) {
|
||||
Region region = pHeader->gamecode[3];
|
||||
if (
|
||||
memcmp(pHeader->gamecode, GAMECODE_PREFIX, 3) != 0 || (
|
||||
region != REGION_JAPAN &&
|
||||
region != REGION_USA &&
|
||||
region != REGION_EUROPE
|
||||
)
|
||||
) {
|
||||
FATAL("Invalid gamecode prefix '%.4s'\n", pHeader->gamecode);
|
||||
}
|
||||
Region region = pHeader->gamecode[3];
|
||||
if (
|
||||
memcmp(pHeader->gamecode, GAMECODE_PREFIX, 3) != 0 || (
|
||||
region != REGION_JAPAN &&
|
||||
region != REGION_USA &&
|
||||
region != REGION_EUROPE
|
||||
)
|
||||
) {
|
||||
FATAL("Invalid gamecode prefix '%.4s'\n", pHeader->gamecode);
|
||||
}
|
||||
|
||||
pInfo->region = region;
|
||||
return true;
|
||||
pInfo->region = region;
|
||||
return true;
|
||||
}
|
||||
|
||||
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);
|
||||
return true;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtractTitle(const char *language, const char *file, 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 *fp = fopen(file, "wb");
|
||||
if (fp == NULL) FATAL("Failed to create %s banner title '%s'\n", language, file);
|
||||
|
||||
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);
|
||||
return true;
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtractBanner(const Banner *pBanner, const BuildInfo *pInfo) {
|
||||
if (!MakeDir(BANNER_SUBDIR)) return 1;
|
||||
if (!MakeDir(BANNER_SUBDIR)) return 1;
|
||||
|
||||
FILE *fp;
|
||||
FILE *fp;
|
||||
|
||||
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) {
|
||||
FATAL("Failed to write banner icon bitmap '" ICON_BITMAP_FILE "'\n");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
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) {
|
||||
FATAL("Failed to write banner icon palette '" ICON_PALETTE_FILE "'\n");
|
||||
}
|
||||
fclose(fp);
|
||||
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) {
|
||||
FATAL("Failed to write banner icon bitmap '" ICON_BITMAP_FILE "'\n");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
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) {
|
||||
FATAL("Failed to write banner icon palette '" ICON_PALETTE_FILE "'\n");
|
||||
}
|
||||
fclose(fp);
|
||||
|
||||
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;
|
||||
if (!ExtractTitle("French", TITLE_FRE_FILE, pBanner->frenchTitle, sizeof(pBanner->frenchTitle))) return false;
|
||||
if (!ExtractTitle("German", TITLE_GER_FILE, pBanner->germanTitle, sizeof(pBanner->germanTitle))) return false;
|
||||
if (!ExtractTitle("Italian", TITLE_ITA_FILE, pBanner->italianTitle, sizeof(pBanner->italianTitle))) return false;
|
||||
if (!ExtractTitle("Spanish", TITLE_SPA_FILE, pBanner->spanishTitle, sizeof(pBanner->spanishTitle))) return false;
|
||||
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;
|
||||
if (!ExtractTitle("French", TITLE_FRE_FILE, pBanner->frenchTitle, sizeof(pBanner->frenchTitle))) return false;
|
||||
if (!ExtractTitle("German", TITLE_GER_FILE, pBanner->germanTitle, sizeof(pBanner->germanTitle))) return false;
|
||||
if (!ExtractTitle("Italian", TITLE_ITA_FILE, pBanner->italianTitle, sizeof(pBanner->italianTitle))) return false;
|
||||
if (!ExtractTitle("Spanish", TITLE_SPA_FILE, pBanner->spanishTitle, sizeof(pBanner->spanishTitle))) return false;
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ExtractAssets(const uint8_t *rom, const uint8_t *fatStart, const uint8_t *fntStart, const FntEntry *pFntEntry) {
|
||||
const uint8_t *subEntryAddr = fntStart + pFntEntry->subtableOffset;
|
||||
const FntSubEntry *pSubEntry = (const FntSubEntry*) subEntryAddr;
|
||||
uint16_t fileId = pFntEntry->firstFile;
|
||||
while(pSubEntry->length > 0) {
|
||||
char name[128];
|
||||
memcpy(name, pSubEntry->name, pSubEntry->length);
|
||||
name[pSubEntry->length] = '\0';
|
||||
|
||||
if (!pSubEntry->isSubdir) {
|
||||
printf("File '%s'\n", name);
|
||||
const uint8_t *subEntryAddr = fntStart + pFntEntry->subtableOffset;
|
||||
const FntSubEntry *pSubEntry = (const FntSubEntry*) subEntryAddr;
|
||||
uint16_t fileId = pFntEntry->firstFile;
|
||||
while(pSubEntry->length > 0) {
|
||||
char name[128];
|
||||
memcpy(name, pSubEntry->name, pSubEntry->length);
|
||||
name[pSubEntry->length] = '\0';
|
||||
|
||||
if (!pSubEntry->isSubdir) {
|
||||
printf("File '%s'\n", name);
|
||||
|
||||
const FatEntry *pFatEntry = (const FatEntry*) fatStart + fileId;
|
||||
size_t fileSize = pFatEntry->endOffset - pFatEntry->startOffset;
|
||||
const uint8_t *pFileBytes = rom + pFatEntry->startOffset;
|
||||
const FatEntry *pFatEntry = (const FatEntry*) fatStart + fileId;
|
||||
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 *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);
|
||||
|
||||
subEntryAddr += sizeof(FntSubEntry) + pSubEntry->length;
|
||||
pSubEntry = (const FntSubEntry*) subEntryAddr;
|
||||
++fileId;
|
||||
continue;
|
||||
}
|
||||
subEntryAddr += sizeof(FntSubEntry) + pSubEntry->length;
|
||||
pSubEntry = (const FntSubEntry*) subEntryAddr;
|
||||
++fileId;
|
||||
continue;
|
||||
}
|
||||
|
||||
printf("Dir '%s'\n", name);
|
||||
if (!MakeDir(name)) return false;
|
||||
if (chdir(name) != 0) FATAL("Failed to enter assets subdirectory '%s'\n", name);
|
||||
|
||||
uint16_t subdirId = READ_SUBDIR_ID(pSubEntry);
|
||||
uint16_t subdirIndex = subdirId & 0xfff;
|
||||
if (!ExtractAssets(rom, fatStart, fntStart, (FntEntry*) fntStart + subdirIndex)) return false;
|
||||
printf("Dir '%s'\n", name);
|
||||
if (!MakeDir(name)) return false;
|
||||
if (chdir(name) != 0) FATAL("Failed to enter assets subdirectory '%s'\n", name);
|
||||
|
||||
uint16_t subdirId = READ_SUBDIR_ID(pSubEntry);
|
||||
uint16_t subdirIndex = subdirId & 0xfff;
|
||||
if (!ExtractAssets(rom, fatStart, fntStart, (FntEntry*) fntStart + subdirIndex)) return false;
|
||||
|
||||
printf("Leave '%s'\n", name);
|
||||
printf("Leave '%s'\n", name);
|
||||
|
||||
if (chdir("..") != 0) FATAL("Failed to leave assets subdirectory '%s'\n", name);
|
||||
subEntryAddr += sizeof(FntSubEntry) + pSubEntry->length + sizeof(subdirId);
|
||||
pSubEntry = (const FntSubEntry*) subEntryAddr;
|
||||
}
|
||||
if (chdir("..") != 0) FATAL("Failed to leave assets subdirectory '%s'\n", name);
|
||||
subEntryAddr += sizeof(FntSubEntry) + pSubEntry->length + sizeof(subdirId);
|
||||
pSubEntry = (const FntSubEntry*) subEntryAddr;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void PrintUsage(const char *program) {
|
||||
@@ -185,7 +185,7 @@ int main(int argc, const char **argv) {
|
||||
}
|
||||
fseek(fpRom, 0, SEEK_END);
|
||||
size_t romSize = ftell(fpRom);
|
||||
fseek(fpRom, 0, SEEK_SET);
|
||||
fseek(fpRom, 0, SEEK_SET);
|
||||
uint8_t *rom = malloc(romSize);
|
||||
if (rom == NULL) {
|
||||
fprintf(stderr, "Failed to allocate buffer for '%s'\n", romFile);
|
||||
@@ -198,36 +198,36 @@ int main(int argc, const char **argv) {
|
||||
fclose(fpRom);
|
||||
|
||||
Header *pHeader = (Header*) rom;
|
||||
BuildInfo info;
|
||||
if (!CheckRegion(pHeader, &info)) return 1;
|
||||
if (!MakeDir(outDir)) return 1;
|
||||
if (chdir(outDir) != 0) {
|
||||
fprintf(stderr, "Failed to enter output directory '%s'\n", outDir);
|
||||
return 1;
|
||||
}
|
||||
BuildInfo info;
|
||||
if (!CheckRegion(pHeader, &info)) return 1;
|
||||
if (!MakeDir(outDir)) return 1;
|
||||
if (chdir(outDir) != 0) {
|
||||
fprintf(stderr, "Failed to enter output directory '%s'\n", outDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!ExtractArm7(rom, &pHeader->arm7)) return 1;
|
||||
if (!ExtractArm7(rom, &pHeader->arm7)) return 1;
|
||||
|
||||
Banner *pBanner = (Banner*) (rom + pHeader->bannerOffset);
|
||||
if (!ExtractBanner(pBanner, &info)) return 1;
|
||||
if (!ExtractBanner(pBanner, &info)) return 1;
|
||||
|
||||
if (!MakeDir(ASSETS_SUBDIR)) return 1;
|
||||
if (chdir(ASSETS_SUBDIR) != 0) {
|
||||
fprintf(stderr, "Failed to enter assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
const uint8_t *fntStart = rom + pHeader->fileNames.offset;
|
||||
const uint8_t *fatStart = rom + pHeader->fileAllocs.offset;
|
||||
if (!ExtractAssets(rom, fatStart, fntStart, (FntEntry*) fntStart)) return 1;
|
||||
if (chdir("..") != 0) {
|
||||
fprintf(stderr, "Failed to leave assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chdir("..") != 0) {
|
||||
fprintf(stderr, "Failed to leave output directory '%s'\n", outDir);
|
||||
return 1;
|
||||
}
|
||||
if (!MakeDir(ASSETS_SUBDIR)) return 1;
|
||||
if (chdir(ASSETS_SUBDIR) != 0) {
|
||||
fprintf(stderr, "Failed to enter assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
const uint8_t *fntStart = rom + pHeader->fileNames.offset;
|
||||
const uint8_t *fatStart = rom + pHeader->fileAllocs.offset;
|
||||
if (!ExtractAssets(rom, fatStart, fntStart, (FntEntry*) fntStart)) return 1;
|
||||
if (chdir("..") != 0) {
|
||||
fprintf(stderr, "Failed to leave assets directory '" ASSETS_SUBDIR "'\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (chdir("..") != 0) {
|
||||
fprintf(stderr, "Failed to leave output directory '%s'\n", outDir);
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(rom);
|
||||
}
|
||||
|
||||
+110
-110
@@ -5,141 +5,141 @@
|
||||
#include "rom.h"
|
||||
|
||||
typedef struct FileTree {
|
||||
struct FileTree *children;
|
||||
uint16_t numChildren;
|
||||
uint16_t maxChildren;
|
||||
uint16_t firstFileId;
|
||||
FntSubEntry *entry;
|
||||
struct FileTree *children;
|
||||
uint16_t numChildren;
|
||||
uint16_t maxChildren;
|
||||
uint16_t firstFileId;
|
||||
FntSubEntry *entry;
|
||||
} FileTree;
|
||||
|
||||
bool MakeFileTree(FileTree *pTree);
|
||||
|
||||
bool IterFiles(bool (*callback)(const char *name, bool isDir, void*), void *userData) {
|
||||
#ifdef _WIN32
|
||||
WIN32_FIND_DATAA findData;
|
||||
HANDLE hFind = FindFirstFileA("*", &findData);
|
||||
if (hFind == INVALID_HANDLE_VALUE) FATAL("Failed to open directory to iterate files\n");
|
||||
do {
|
||||
const char *name = findData.cFileName;
|
||||
WIN32_FIND_DATAA findData;
|
||||
HANDLE hFind = FindFirstFileA("*", &findData);
|
||||
if (hFind == INVALID_HANDLE_VALUE) FATAL("Failed to open directory to iterate files\n");
|
||||
do {
|
||||
const char *name = findData.cFileName;
|
||||
if (strcmp(name, ".") == 0) continue;
|
||||
if (strcmp(name, "..") == 0) continue;
|
||||
bool isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
if (!callback(name, isDir, userData)) return false;
|
||||
} while (FindNextFileA(hFind, &findData));
|
||||
FindClose(hFind);
|
||||
bool isDir = (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
if (!callback(name, isDir, userData)) return false;
|
||||
} while (FindNextFileA(hFind, &findData));
|
||||
FindClose(hFind);
|
||||
#elif __linux__
|
||||
DIR *dir = opendir(".");
|
||||
struct dirent entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
const char *name = entry->d_name;
|
||||
bool isDir = entry->d_type == DT_DIR;
|
||||
if (!callback(name, isDir, userData)) return false;
|
||||
}
|
||||
closedir(dir);
|
||||
DIR *dir = opendir(".");
|
||||
struct dirent entry;
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
const char *name = entry->d_name;
|
||||
bool isDir = entry->d_type == DT_DIR;
|
||||
if (!callback(name, isDir, userData)) return false;
|
||||
}
|
||||
closedir(dir);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool _GrowFileTreeChildren(FileTree *pTree, size_t minChildren) {
|
||||
FileTree tree;
|
||||
memcpy(&tree, pTree, sizeof(tree));
|
||||
if (tree.maxChildren >= minChildren) return true;
|
||||
FileTree tree;
|
||||
memcpy(&tree, pTree, sizeof(tree));
|
||||
if (tree.maxChildren >= minChildren) return true;
|
||||
|
||||
size_t newSize = tree.maxChildren;
|
||||
if (newSize == 0) newSize = minChildren;
|
||||
while (newSize < minChildren) newSize *= 2;
|
||||
if (tree.children == NULL) {
|
||||
FileTree *children = malloc(newSize * sizeof(FileTree));
|
||||
if (children == NULL) FATAL("Failed to allocate file tree children\n");
|
||||
tree.children = children;
|
||||
} else {
|
||||
FileTree *children = realloc(tree.children, newSize * sizeof(FileTree));
|
||||
if (children == NULL) FATAL("Failed to reallocate file tree children\n");
|
||||
tree.children = children;
|
||||
}
|
||||
tree.maxChildren = newSize;
|
||||
size_t newSize = tree.maxChildren;
|
||||
if (newSize == 0) newSize = minChildren;
|
||||
while (newSize < minChildren) newSize *= 2;
|
||||
if (tree.children == NULL) {
|
||||
FileTree *children = malloc(newSize * sizeof(FileTree));
|
||||
if (children == NULL) FATAL("Failed to allocate file tree children\n");
|
||||
tree.children = children;
|
||||
} else {
|
||||
FileTree *children = realloc(tree.children, newSize * sizeof(FileTree));
|
||||
if (children == NULL) FATAL("Failed to reallocate file tree children\n");
|
||||
tree.children = children;
|
||||
}
|
||||
tree.maxChildren = newSize;
|
||||
|
||||
memcpy(pTree, &tree, sizeof(tree));
|
||||
return true;
|
||||
memcpy(pTree, &tree, sizeof(tree));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FileTreeFileCallback(const char *name, bool isDir, void *userData) {
|
||||
FileTree *pTree = (FileTree*) userData;
|
||||
size_t nameLength = strlen(name);
|
||||
FileTree *pTree = (FileTree*) userData;
|
||||
size_t nameLength = strlen(name);
|
||||
|
||||
if (isDir) {
|
||||
FntSubEntry *entry = malloc(sizeof(FntSubEntry) + nameLength + 2);
|
||||
if (entry == NULL) FATAL("Failed to allocate FNT sub entry for directory '%s'\n", name);
|
||||
entry->isSubdir = true;
|
||||
entry->length = nameLength;
|
||||
memcpy(entry->name, name, nameLength);
|
||||
WRITE_SUBDIR_ID(entry, 0);
|
||||
if (isDir) {
|
||||
FntSubEntry *entry = malloc(sizeof(FntSubEntry) + nameLength + 2);
|
||||
if (entry == NULL) FATAL("Failed to allocate FNT sub entry for directory '%s'\n", name);
|
||||
entry->isSubdir = true;
|
||||
entry->length = nameLength;
|
||||
memcpy(entry->name, name, nameLength);
|
||||
WRITE_SUBDIR_ID(entry, 0);
|
||||
|
||||
if (chdir(name) != 0) FATAL("Failed to enter directory '%s'\n", name);
|
||||
if (chdir(name) != 0) FATAL("Failed to enter directory '%s'\n", name);
|
||||
|
||||
FileTree child;
|
||||
if (!MakeFileTree(&child)) return false;
|
||||
child.entry = entry;
|
||||
if (!_GrowFileTreeChildren(pTree, pTree->numChildren + 1)) return false;
|
||||
memcpy(&pTree->children[pTree->numChildren], &child, sizeof(child));
|
||||
pTree->numChildren += 1;
|
||||
FileTree child;
|
||||
if (!MakeFileTree(&child)) return false;
|
||||
child.entry = entry;
|
||||
if (!_GrowFileTreeChildren(pTree, pTree->numChildren + 1)) return false;
|
||||
memcpy(&pTree->children[pTree->numChildren], &child, sizeof(child));
|
||||
pTree->numChildren += 1;
|
||||
|
||||
if (chdir("..") != 0) FATAL("Failed to leave directory '%s'\n", name);
|
||||
} else {
|
||||
FntSubEntry *entry = malloc(sizeof(FntSubEntry) + nameLength);
|
||||
if (entry == NULL) FATAL("Failed to allocate FNT sub entry for file '%s'\n", name);
|
||||
entry->isSubdir = false;
|
||||
entry->length = nameLength;
|
||||
memcpy(entry->name, name, nameLength);
|
||||
if (chdir("..") != 0) FATAL("Failed to leave directory '%s'\n", name);
|
||||
} else {
|
||||
FntSubEntry *entry = malloc(sizeof(FntSubEntry) + nameLength);
|
||||
if (entry == NULL) FATAL("Failed to allocate FNT sub entry for file '%s'\n", name);
|
||||
entry->isSubdir = false;
|
||||
entry->length = nameLength;
|
||||
memcpy(entry->name, name, nameLength);
|
||||
|
||||
FileTree child;
|
||||
child.children = NULL;
|
||||
child.numChildren = 0;
|
||||
child.maxChildren = 0;
|
||||
child.firstFileId = 0;
|
||||
child.entry = entry;
|
||||
if (!_GrowFileTreeChildren(pTree, pTree->numChildren + 1)) return false;
|
||||
memcpy(&pTree->children[pTree->numChildren], &child, sizeof(child));
|
||||
pTree->numChildren += 1;
|
||||
}
|
||||
FileTree child;
|
||||
child.children = NULL;
|
||||
child.numChildren = 0;
|
||||
child.maxChildren = 0;
|
||||
child.firstFileId = 0;
|
||||
child.entry = entry;
|
||||
if (!_GrowFileTreeChildren(pTree, pTree->numChildren + 1)) return false;
|
||||
memcpy(&pTree->children[pTree->numChildren], &child, sizeof(child));
|
||||
pTree->numChildren += 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MakeFileTree(FileTree *pTree) {
|
||||
FileTree tree;
|
||||
FileTree tree;
|
||||
tree.children = NULL;
|
||||
tree.numChildren = 0;
|
||||
tree.maxChildren = 0;
|
||||
if (!_GrowFileTreeChildren(&tree, 64)) return false;
|
||||
tree.entry = NULL;
|
||||
tree.numChildren = 0;
|
||||
tree.maxChildren = 0;
|
||||
if (!_GrowFileTreeChildren(&tree, 64)) return false;
|
||||
tree.entry = NULL;
|
||||
|
||||
if (!IterFiles(_FileTreeFileCallback, &tree)) return false;
|
||||
memcpy(pTree, &tree, sizeof(tree));
|
||||
return true;
|
||||
if (!IterFiles(_FileTreeFileCallback, &tree)) return false;
|
||||
memcpy(pTree, &tree, sizeof(tree));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FreeFileTree(FileTree *pTree) {
|
||||
for (size_t i = 0; i < pTree->numChildren; ++i) {
|
||||
if (!FreeFileTree(&pTree->children[i])) return false;
|
||||
}
|
||||
if (pTree->children != NULL) {
|
||||
free(pTree->children);
|
||||
pTree->children = NULL;
|
||||
}
|
||||
pTree->numChildren = 0;
|
||||
pTree->maxChildren = 0;
|
||||
if (pTree->entry != NULL) {
|
||||
free(pTree->entry);
|
||||
pTree->entry = NULL;
|
||||
}
|
||||
for (size_t i = 0; i < pTree->numChildren; ++i) {
|
||||
if (!FreeFileTree(&pTree->children[i])) return false;
|
||||
}
|
||||
if (pTree->children != NULL) {
|
||||
free(pTree->children);
|
||||
pTree->children = NULL;
|
||||
}
|
||||
pTree->numChildren = 0;
|
||||
pTree->maxChildren = 0;
|
||||
if (pTree->entry != NULL) {
|
||||
free(pTree->entry);
|
||||
pTree->entry = NULL;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int CompareFileTree(const void *a, const void *b) {
|
||||
FileTree *treeA = (FileTree*) a;
|
||||
FileTree *treeB = (FileTree*) b;
|
||||
size_t lenA = treeA->entry->length;
|
||||
size_t lenB = treeB->entry->length;
|
||||
size_t minSize = (lenA < lenB) ? lenA : lenB;
|
||||
FileTree *treeA = (FileTree*) a;
|
||||
FileTree *treeB = (FileTree*) b;
|
||||
size_t lenA = treeA->entry->length;
|
||||
size_t lenB = treeB->entry->length;
|
||||
size_t minSize = (lenA < lenB) ? lenA : lenB;
|
||||
|
||||
const char *nameA = treeA->entry->name;
|
||||
const char *nameB = treeB->entry->name;
|
||||
@@ -148,23 +148,23 @@ int CompareFileTree(const void *a, const void *b) {
|
||||
const char chB = tolower(nameB[i]);
|
||||
if (chA != chB) return chA - chB;
|
||||
}
|
||||
if (lenA < lenB) return -1;
|
||||
if (lenA > lenB) return 1;
|
||||
return 0;
|
||||
if (lenA < lenB) return -1;
|
||||
if (lenA > lenB) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SortFileTree(FileTree *pTree) {
|
||||
if (pTree->numChildren <= 1) return true;
|
||||
FileTree tree;
|
||||
memcpy(&tree, pTree, sizeof(tree));
|
||||
FileTree tree;
|
||||
memcpy(&tree, pTree, sizeof(tree));
|
||||
|
||||
qsort(tree.children, tree.numChildren, sizeof(*tree.children), CompareFileTree);
|
||||
for (size_t i = 0; i < tree.numChildren; ++i) {
|
||||
if (!SortFileTree(&tree.children[i])) return false;
|
||||
}
|
||||
qsort(tree.children, tree.numChildren, sizeof(*tree.children), CompareFileTree);
|
||||
for (size_t i = 0; i < tree.numChildren; ++i) {
|
||||
if (!SortFileTree(&tree.children[i])) return false;
|
||||
}
|
||||
|
||||
memcpy(pTree, &tree, sizeof(tree));
|
||||
return true;
|
||||
memcpy(pTree, &tree, sizeof(tree));
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+14
-14
@@ -80,29 +80,29 @@ typedef struct {
|
||||
} Banner;
|
||||
|
||||
typedef struct {
|
||||
/* 0 */ uint32_t subtableOffset;
|
||||
/* 4 */ uint16_t firstFile;
|
||||
/* 6 */ uint16_t parentId;
|
||||
/* 8 */
|
||||
/* 0 */ uint32_t subtableOffset;
|
||||
/* 4 */ uint16_t firstFile;
|
||||
/* 6 */ uint16_t parentId;
|
||||
/* 8 */
|
||||
} FntEntry;
|
||||
|
||||
typedef struct {
|
||||
/* 0.0 */ uint8_t length : 7;
|
||||
/* 0.7 */ bool isSubdir : 1;
|
||||
/* 1.0 */ char name[];
|
||||
// If isSubdir
|
||||
/* 1.0 + length */ // uint16_t subdirId;
|
||||
/* 1.0 + length + 2 */
|
||||
// Else
|
||||
/* 1.0 + length */
|
||||
/* 0.0 */ uint8_t length : 7;
|
||||
/* 0.7 */ bool isSubdir : 1;
|
||||
/* 1.0 */ char name[];
|
||||
// If isSubdir
|
||||
/* 1.0 + length */ // uint16_t subdirId;
|
||||
/* 1.0 + length + 2 */
|
||||
// Else
|
||||
/* 1.0 + length */
|
||||
} FntSubEntry;
|
||||
|
||||
#define READ_SUBDIR_ID(entry) READ16(entry + sizeof(*entry) + entry->length);
|
||||
#define WRITE_SUBDIR_ID(entry,id) WRITE16(entry + sizeof(*entry) + entry->length, id)
|
||||
|
||||
typedef struct {
|
||||
/* 0 */ uint32_t startOffset;
|
||||
/* 4 */ uint32_t endOffset;
|
||||
/* 0 */ uint32_t startOffset;
|
||||
/* 4 */ uint32_t endOffset;
|
||||
} FatEntry;
|
||||
|
||||
#endif
|
||||
|
||||
+11
-11
@@ -28,18 +28,18 @@
|
||||
|
||||
bool WcharToUtf8(wchar_t *in, size_t inSize, char *out, size_t outSize, size_t *pResultSize) {
|
||||
#ifdef _WIN32
|
||||
size_t resultSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, in, inSize / sizeof(wchar_t), out, outSize, NULL, NULL);
|
||||
if (resultSize == 0) FATAL("Failed to convert to UTF-8\n");
|
||||
*pResultSize = resultSize;
|
||||
return true;
|
||||
size_t resultSize = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, in, inSize / sizeof(wchar_t), out, outSize, NULL, NULL);
|
||||
if (resultSize == 0) FATAL("Failed to convert to UTF-8\n");
|
||||
*pResultSize = resultSize;
|
||||
return true;
|
||||
#elif __linux__
|
||||
iconv_t convDesc = iconv_open("UTF-16", "UTF-8");
|
||||
if (convDesc == -1) FATAL("Failed to get conversion description to UTF-8\n");
|
||||
size_t remainingBytes = outSize;
|
||||
if (iconv(convDesc, &in, &inSize, &out, &remainingBytes) == -1) FATAL("Failed to convert to UTF-8\n");
|
||||
if (inSize > 0) FATAL("Some characters were not converted to UTF-8\n");
|
||||
*pResultSize = outSize - remainingBytes;
|
||||
return true;
|
||||
iconv_t convDesc = iconv_open("UTF-16", "UTF-8");
|
||||
if (convDesc == -1) FATAL("Failed to get conversion description to UTF-8\n");
|
||||
size_t remainingBytes = outSize;
|
||||
if (iconv(convDesc, &in, &inSize, &out, &remainingBytes) == -1) FATAL("Failed to convert to UTF-8\n");
|
||||
if (inSize > 0) FATAL("Some characters were not converted to UTF-8\n");
|
||||
*pResultSize = outSize - remainingBytes;
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user