Added returning to the last dir a ROM was launched from on next boot. Fixes #21.
This commit is contained in:
parent
ffb32cca9c
commit
c87769a06e
|
@ -25,3 +25,4 @@
|
|||
|
||||
Result fsQuickRead(const char *const path, void *const buf, u32 size);
|
||||
Result fsQuickWrite(const char *const path, const void *const buf, u32 size);
|
||||
Result fsMakePath(const char *const path);
|
||||
|
|
|
@ -26,7 +26,26 @@
|
|||
|
||||
|
||||
|
||||
NAKED void wait(u32 cycles);
|
||||
/**
|
||||
* @brief Waits at least the specified amount of CPU cycles.
|
||||
*
|
||||
* @param[in] cycles The cycles to wait.
|
||||
*/
|
||||
NAKED void wait_cycles(u32 cycles);
|
||||
|
||||
/**
|
||||
* @brief Safer strcpy with checks.
|
||||
* The dst string always gets terminated except when num is 0.
|
||||
* If the src string is too long nothing is copied and dst will be terminated.
|
||||
* This function is not safe against race conditions!
|
||||
*
|
||||
* @param dst The destination pointer.
|
||||
* @param[in] src The source pointer.
|
||||
* @param[in] num Maximum number of chars to copy including null terminator.
|
||||
*
|
||||
* @return The length of the copied string in bytes including null terminator.
|
||||
*/
|
||||
size_t safeStrcpy(char *const dst, const char *const src, size_t num);
|
||||
|
||||
// case insensitive string compare function
|
||||
int strnicmp(const char *str1, const char *str2, u32 len);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "types.h"
|
||||
#include "error_codes.h"
|
||||
#include "fs.h"
|
||||
#include "util.h"
|
||||
#include "arm11/hardware/hid.h"
|
||||
#include "arm11/fmt.h"
|
||||
#include "hardware/gfx.h"
|
||||
|
@ -17,7 +18,7 @@
|
|||
typedef struct
|
||||
{
|
||||
u8 type; // 0 = file, 1 = dir
|
||||
char str[255];
|
||||
char str[256];
|
||||
} DirListEnt;
|
||||
|
||||
typedef struct
|
||||
|
@ -29,22 +30,6 @@ typedef struct
|
|||
|
||||
|
||||
|
||||
// num including null terminator.
|
||||
static size_t safeStrcpy(char *const dst, const char *const src, size_t num)
|
||||
{
|
||||
if(num == 0) return 0;
|
||||
|
||||
const size_t len = strlen(src) + 1;
|
||||
if(len > num)
|
||||
{
|
||||
*dst = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
strcpy(dst, src);
|
||||
return len;
|
||||
}
|
||||
|
||||
int dlistCompare(const void *a, const void *b)
|
||||
{
|
||||
const DirListEnt *const entA = *(DirListEnt**)a;
|
||||
|
@ -90,7 +75,7 @@ static Result scanDir(const char *const path, DirList *const dList, const char *
|
|||
}
|
||||
|
||||
dList->entries[dListPos].type = isDir;
|
||||
safeStrcpy(dList->entries[dListPos].str, fi[i].fname, 255);
|
||||
safeStrcpy(dList->entries[dListPos].str, fi[i].fname, 256);
|
||||
dList->ptrs[dListPos] = &dList->entries[dListPos];
|
||||
dListPos++;
|
||||
}
|
||||
|
@ -196,7 +181,7 @@ Result browseFiles(const char *const basePath, char selected[512])
|
|||
{
|
||||
// TODO: !!! Insecure !!!
|
||||
if(curDir[pathLen - 1] != '/') curDir[pathLen++] = '/';
|
||||
safeStrcpy(curDir + pathLen, dList->ptrs[cursorPos]->str, 255);
|
||||
safeStrcpy(curDir + pathLen, dList->ptrs[cursorPos]->str, 256);
|
||||
|
||||
if(dList->ptrs[cursorPos]->type == 0)
|
||||
{
|
||||
|
|
|
@ -74,7 +74,7 @@ void GFX_init(GfxFbFmt fmtTop, GfxFbFmt fmtBot)
|
|||
|
||||
// Reset
|
||||
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E;
|
||||
wait(12);
|
||||
wait_cycles(12);
|
||||
REG_PDN_GPU_CNT = PDN_GPU_CNT_CLK_E | PDN_GPU_CNT_RST_ALL;
|
||||
REG_GX_GPU_CLK = 0x100;
|
||||
REG_GX_PSC_VRAM = 0;
|
||||
|
@ -452,7 +452,7 @@ void GX_textureCopy(const u32 *const in, u32 indim, u32 *out, u32 outdim, u32 si
|
|||
void GX_processCommandList(u32 size, const u32 *const cmdList)
|
||||
{
|
||||
REG_GX_P3D(GPUREG_IRQ_ACK) = 0; // Acknowledge last P3D.
|
||||
while(REG_GX_PSC_STAT & 1u<<31) wait(0x30);
|
||||
while(REG_GX_PSC_STAT & 1u<<31) wait_cycles(0x30);
|
||||
|
||||
REG_GX_P3D(GPUREG_CMDBUF_SIZE0) = size>>3;
|
||||
REG_GX_P3D(GPUREG_CMDBUF_ADDR0) = (u32)cmdList>>3;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "arm11/power.h"
|
||||
#include "hardware/gfx.h"
|
||||
#include "fs.h"
|
||||
#include "fsutil.h"
|
||||
#include "arm11/filebrowser.h"
|
||||
#include "arm.h"
|
||||
#include "arm11/hardware/lcd.h"
|
||||
|
@ -41,6 +42,9 @@
|
|||
#include "kevent.h"
|
||||
|
||||
|
||||
#define OAF_WORK_DIR "sdmc:/3ds/open_agb_firm"
|
||||
|
||||
|
||||
|
||||
static u32 padRomArea(u32 romFileSize)
|
||||
{
|
||||
|
@ -265,7 +269,7 @@ saveTypeFound:
|
|||
return saveType;
|
||||
}
|
||||
|
||||
u16 saveDbDebug(const char *const savePath, u32 romSize)
|
||||
static u16 saveDbDebug(const char *const savePath, u32 romSize)
|
||||
{
|
||||
FILINFO fi;
|
||||
const bool saveExists = fStat(savePath, &fi) == RES_OK;
|
||||
|
@ -470,7 +474,7 @@ static void gbaGfxHandler(void *args)
|
|||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void debugTests(void)
|
||||
static void debugTests(void)
|
||||
{
|
||||
const u32 kDown = hidKeysDown();
|
||||
|
||||
|
@ -500,6 +504,52 @@ void debugTests(void)
|
|||
}
|
||||
#endif
|
||||
|
||||
static Result handleFsStuff(char romPath[512])
|
||||
{
|
||||
// Mount SD card.
|
||||
Result res;
|
||||
if((res = fMount(FS_DRIVE_SDMC)) == RES_OK)
|
||||
{
|
||||
char *lastDir = (char*)calloc(512, 1);
|
||||
if(lastDir != NULL)
|
||||
{
|
||||
do
|
||||
{
|
||||
// Create working dir.
|
||||
if((res = fsMakePath(OAF_WORK_DIR)) != RES_OK && res != RES_FR_EXIST) break;
|
||||
|
||||
// Get last ROM launch path.
|
||||
if((res = fsQuickRead(OAF_WORK_DIR "/lastdir.bin", lastDir, 511)) != RES_OK)
|
||||
{
|
||||
if(res == RES_FR_NO_FILE) strcpy(lastDir, "sdmc:/");
|
||||
else break;
|
||||
}
|
||||
|
||||
// Show file browser.
|
||||
*romPath = '\0';
|
||||
if((res = browseFiles(lastDir, romPath)) != RES_OK) break;
|
||||
|
||||
size_t cmpLen = strrchr(romPath, '/') - romPath;
|
||||
if((size_t)(strchr(romPath, '/') - romPath) == cmpLen) cmpLen++; // Keep the first '/'.
|
||||
if(cmpLen < 512)
|
||||
{
|
||||
if(cmpLen < strlen(lastDir) || strncmp(lastDir, romPath, cmpLen) != 0)
|
||||
{
|
||||
strncpy(lastDir, romPath, cmpLen);
|
||||
lastDir[cmpLen] = '\0';
|
||||
res = fsQuickWrite(OAF_WORK_DIR "/lastdir.bin", lastDir, cmpLen + 1);
|
||||
}
|
||||
}
|
||||
} while(0);
|
||||
|
||||
free(lastDir);
|
||||
}
|
||||
else res = RES_OUT_OF_MEM;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
GFX_init(GFX_BGR8, GFX_RGB565);
|
||||
|
@ -507,12 +557,9 @@ int main(void)
|
|||
consoleInit(SCREEN_BOT, NULL);
|
||||
//CODEC_init();
|
||||
|
||||
// Show file browser.
|
||||
Result res;
|
||||
char *romPath = (char*)malloc(512);
|
||||
*romPath = '\0';
|
||||
if((res = fMount(FS_DRIVE_SDMC)) != RES_OK || (res = browseFiles("sdmc:/", romPath)) != RES_OK || *romPath == '\0')
|
||||
goto end;
|
||||
Result res = handleFsStuff(romPath);
|
||||
if(res != RES_OK || *romPath == '\0') goto end;
|
||||
|
||||
ee_puts("Reading ROM and save...");
|
||||
u32 romSize;
|
||||
|
|
|
@ -470,7 +470,7 @@ int SD_Init()
|
|||
set_target(&handleSD);
|
||||
// TMIO base clock is half of the CPU clock so 2 CPU cycles = 1 base clock pulse.
|
||||
// cycles = 2 * [TMIO clock divider] * 74
|
||||
wait(2 * 128 * 74);
|
||||
wait_cycles(2 * 128 * 74);
|
||||
|
||||
sdmmc_send_command(&handleSD,0,0);
|
||||
sdmmc_send_command(&handleSD,0x10408,0x1AA);
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <string.h>
|
||||
#include "fsutil.h"
|
||||
#include "fs.h"
|
||||
#include "util.h"
|
||||
|
||||
|
||||
|
||||
|
@ -54,3 +55,30 @@ Result fsQuickWrite(const char *const path, const void *const buf, u32 size)
|
|||
|
||||
return res;
|
||||
}
|
||||
|
||||
Result fsMakePath(const char *const path)
|
||||
{
|
||||
char tmpPath[512];
|
||||
safeStrcpy(tmpPath, path, 512);
|
||||
|
||||
char *str;
|
||||
if((str = strchr(tmpPath, ':')) == NULL) str = tmpPath;
|
||||
else str++;
|
||||
|
||||
// Path without any dir.
|
||||
if(*str == '\0') return RES_INVALID_ARG;
|
||||
|
||||
Result res = RES_OK;
|
||||
while((str = strchr(str + 1, '/')) != NULL)
|
||||
{
|
||||
*str = '\0';
|
||||
if((res = fMkdir(tmpPath)) != RES_OK && res != RES_FR_EXIST) break;
|
||||
*str = '/';
|
||||
}
|
||||
|
||||
// Only create the last dir in the path if the
|
||||
// previous error code is not an unexpected one.
|
||||
if(res == RES_OK || res == RES_FR_EXIST) res = fMkdir(tmpPath);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
|
||||
|
||||
NAKED void wait(u32 cycles)
|
||||
NAKED void wait_cycles(u32 cycles)
|
||||
{
|
||||
#ifdef ARM9
|
||||
__asm__("1: subs %0, %0, #4\n\t"
|
||||
|
@ -35,6 +35,22 @@ NAKED void wait(u32 cycles)
|
|||
"bx lr\n\t" : : "r" (cycles) : "cc");
|
||||
}
|
||||
|
||||
size_t safeStrcpy(char *const dst, const char *const src, size_t num)
|
||||
{
|
||||
if(num == 0) return 0;
|
||||
|
||||
const size_t len = strlen(src) + 1;
|
||||
if(len > num)
|
||||
{
|
||||
*dst = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
strcpy(dst, src);
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// case insensitive string compare function
|
||||
int strnicmp(const char *str1, const char *str2, u32 len)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue