TDT/arm9/src/rom.c
Pk11 68fc9a6586 Clean up formatting
No code changes outside of a very minor change to arm7/main.c (removes unused functions)
2022-01-14 22:42:47 -06:00

295 lines
5.7 KiB
C

#include "rom.h"
#include "main.h"
#include "storage.h"
#include <dirent.h>
#include <nds.h>
#include <malloc.h>
#include <stdio.h>
tDSiHeader* getRomHeader(char const* fpath)
{
if (!fpath) return NULL;
tDSiHeader* h = NULL;
FILE* f = fopen(fpath, "rb");
if (f)
{
h = (tDSiHeader*)malloc(sizeof(tDSiHeader));
if (h)
{
if (romIsCia(fpath))
fseek(f, 0x3900, SEEK_SET);
else
fseek(f, 0, SEEK_SET);
fread(h, sizeof(tDSiHeader), 1, f);
}
fclose(f);
}
return h;
}
tNDSBanner* getRomBanner(char const* fpath)
{
if (!fpath) return NULL;
tDSiHeader* h = getRomHeader(fpath);
tNDSBanner* b = NULL;
if (h)
{
FILE* f = fopen(fpath, "rb");
if (f)
{
b = (tNDSBanner*)malloc(sizeof(tNDSBanner));
if (b)
{
if (romIsCia(fpath))
fseek(f, 0x3900, SEEK_SET);
else
fseek(f, 0, SEEK_SET);
fseek(f, h->ndshdr.bannerOffset, SEEK_CUR);
fread(b, sizeof(tNDSBanner), 1, f);
}
}
free(h);
fclose(f);
}
return b;
}
bool getGameTitle(tNDSBanner* b, char* out, bool full)
{
if (!b) return false;
if (!out) return false;
//get system language
int lang = PersonalData->language;
//not japanese or chinese
if (lang == 0 || lang == 6)
lang = 1;
//read title
u16 c;
for (int i = 0; i < 128; i++)
{
c = b->titles[lang][i];
//remove accents
if (c == 0x00F3)
c = 'o';
if (c == 0x00E1)
c = 'a';
out[i] = (char)c;
if (!full && out[i] == '\n')
{
out[i] = '\0';
break;
}
}
out[128] = '\0';
return true;
}
bool getGameTitlePath(char const* fpath, char* out, bool full)
{
if (!fpath) return false;
if (!out) return false;
tNDSBanner* b = getRomBanner(fpath);
bool result = getGameTitle(b, out, full);
free(b);
return result;
}
bool getRomLabel(tDSiHeader* h, char* out)
{
if (!h) return false;
if (!out) return false;
sprintf(out, "%.12s", h->ndshdr.gameTitle);
return true;
}
bool getRomCode(tDSiHeader* h, char* out)
{
if (!h) return false;
if (!out) return false;
sprintf(out, "%.4s", h->ndshdr.gameCode);
return true;
}
void printRomInfo(char const* fpath)
{
clearScreen(&topScreen);
if (!fpath) return;
tDSiHeader* h = getRomHeader(fpath);
tNDSBanner* b = getRomBanner(fpath);
if (!isDsiHeader(h))
{
iprintf("Could not read dsi header.\n");
}
else
{
if (!b)
{
iprintf("Could not read banner.\n");
}
else
{
//proper title
{
char gameTitle[128+1];
getGameTitle(b, gameTitle, true);
iprintf("%s\n\n", gameTitle);
}
//file size
{
iprintf("Size: ");
unsigned long long romSize = getRomSize(fpath);
printBytes(romSize);
//size in blocks, rounded up
iprintf(" (%lld blocks)\n", ((romSize / BYTES_PER_BLOCK) * BYTES_PER_BLOCK + BYTES_PER_BLOCK) / BYTES_PER_BLOCK);
}
iprintf("Label: %.12s\n", h->ndshdr.gameTitle);
iprintf("Game Code: %.4s\n", h->ndshdr.gameCode);
//system type
{
iprintf("Unit Code: ");
switch (h->ndshdr.unitCode)
{
case 0: iprintf("NDS"); break;
case 2: iprintf("NDS+DSi"); break;
case 3: iprintf("DSi"); break;
default: iprintf("unknown");
}
iprintf("\n");
}
//application type
{
iprintf("Program Type: ");
switch (h->ndshdr.reserved1[7])
{
case 0x3: iprintf("Normal"); break;
case 0xB: iprintf("Sys"); break;
case 0xF: iprintf("Debug/Sys"); break;
default: iprintf("unknown");
}
iprintf("\n");
}
//DSi title ids
{
if (h->tid_high == 0x00030004 ||
h->tid_high == 0x00030005 ||
h->tid_high == 0x00030015 ||
h->tid_high == 0x00030017 ||
h->tid_high == 0x00030000)
{
iprintf("Title ID: %08x %08x\n", (unsigned int)h->tid_high, (unsigned int)h->tid_low);
}
}
//print full file path
iprintf("\n%s\n", fpath);
//print extra files
int extensionPos = strrchr(fpath, '.') - fpath;
char temp[PATH_MAX];
strcpy(temp, fpath);
strcpy(temp + extensionPos, ".tmd");
//DSi TMDs are 520, TMDs from NUS are 2,312. If 2,312 we can simply trim it to 520
int tmdSize = getFileSizePath(temp);
if (access(temp, F_OK) == 0)
printf("\t\x1B[%om%s\n\x1B[47m", (tmdSize == 520 || tmdSize == 2312) ? 047 : 041, strrchr(temp, '/') + 1);
strcpy(temp + extensionPos, ".pub");
if (access(temp, F_OK) == 0)
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == h->public_sav_size) ? 047 : 041, strrchr(temp, '/') + 1);
strcpy(temp + extensionPos, ".prv");
if (access(temp, F_OK) == 0)
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == h->private_sav_size) ? 047 : 041, strrchr(temp, '/') + 1);
strcpy(temp + extensionPos, ".bnr");
if (access(temp, F_OK) == 0)
printf("\t\x1B[%om%s\n\x1B[47m", (getFileSizePath(temp) == 0x4000) ? 047 : 041, strrchr(temp, '/') + 1);
}
}
free(b);
free(h);
}
unsigned long long getRomSize(char const* fpath)
{
if (!fpath) return 0;
unsigned long long size = 0;
FILE* f = fopen(fpath, "rb");
if (f)
{
//cia
if (romIsCia(fpath))
{
unsigned char bytes[4] = { 0 };
fseek(f, 0x38D0, SEEK_SET);
fread(bytes, 4, 1, f);
size = (bytes[0] << 24) | (bytes[1] << 16) | (bytes[2] << 8) | bytes[3];
}
else
{
fseek(f, 0, SEEK_END);
size = ftell(f);
}
}
fclose(f);
return size;
}
bool romIsCia(char const* fpath)
{
if (!fpath) return false;
return (strstr(fpath, ".cia") != NULL || strstr(fpath, ".CIA") != NULL);
}
bool isDsiHeader(tDSiHeader* h)
{
if (!h) return false;
u16 crc16 = swiCRC16(0xFFFF, h, 0x15E);
return h->ndshdr.headerCRC16 == crc16;
}