Add giattributes

This commit is contained in:
Edoardo Lolletti 2025-04-29 18:22:35 +02:00
parent 5f8f69c2ab
commit d01ccfbf47
9 changed files with 1335 additions and 1334 deletions

1
.gitattributes vendored Normal file
View File

@ -0,0 +1 @@
* text=auto

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +1,25 @@
#ifndef MAIN_H
#define MAIN_H
#include <nds.h>
#include <fat.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
extern volatile bool programEnd;
extern volatile bool charging;
extern volatile u8 batteryLevel;
extern PrintConsole topScreen;
extern PrintConsole bottomScreen;
void clearScreen(PrintConsole* screen);
#ifdef __cplusplus
}
#endif
#ifndef MAIN_H
#define MAIN_H
#include <nds.h>
#include <fat.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
extern volatile bool programEnd;
extern volatile bool charging;
extern volatile u8 batteryLevel;
extern PrintConsole topScreen;
extern PrintConsole bottomScreen;
void clearScreen(PrintConsole* screen);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,237 +1,237 @@
#include "menu.h"
#include "main.h"
#define sign(X) ( ((X) > 0) - ((X) < 0) )
#define repeat(X) for (int _I_ = 0; _I_ < (X); _I_++)
Menu* newMenu()
{
Menu* m = (Menu*)malloc(sizeof(Menu));
m->cursor = 0;
m->page = 0;
m->itemCount = 0;
m->nextPage = false;
m->changePage = 0;
m->header[0] = '\0';
for (int i = 0; i < ITEMS_PER_PAGE; i++)
{
m->items[i].directory = false;
m->items[i].label = NULL;
m->items[i].value = NULL;
}
return m;
}
void freeMenu(Menu* m)
{
if (!m) return;
clearMenu(m);
free(m);
m = NULL;
}
void addMenuItem(Menu* m, char const* label, char const* value, bool enabled, bool directory)
{
if (!m) return;
int i = m->itemCount;
if (i >= ITEMS_PER_PAGE) return;
m->items[i].directory = directory;
m->items[i].enabled = enabled;
if (label)
{
m->items[i].label = (char*)malloc(32);
sprintf(m->items[i].label, "%.31s", label);
}
if (value)
{
m->items[i].value = (char*)malloc(strlen(value)+1);
sprintf(m->items[i].value, "%s", value);
}
m->itemCount += 1;
}
static int alphabeticalCompare(const void* a, const void* b)
{
const Item* itemA = (const Item*)a;
const Item* itemB = (const Item*)b;
if (itemA->directory && !itemB->directory)
return -1;
else if (!itemA->directory && itemB->directory)
return 1;
else
return strcasecmp(itemA->label, itemB->label);
}
void sortMenuItems(Menu* m)
{
qsort(m->items, m->itemCount, sizeof(Item), alphabeticalCompare);
}
void setMenuHeader(Menu* m, const char* str)
{
if (!m) return;
if (!str)
{
m->header[0] = '\0';
return;
}
const char* strPtr = str;
if (strlen(strPtr) > 30)
strPtr = str + (strlen(strPtr) - 30);
sprintf(m->header, "%.30s", strPtr);
}
void resetMenu(Menu* m)
{
m->cursor = 0;
m->page = 0;
m->changePage = 0;
m->nextPage = 0;
}
void clearMenu(Menu* m)
{
if (!m) return;
for (int i = 0; i < ITEMS_PER_PAGE; i++)
{
if (m->items[i].label)
{
free(m->items[i].label);
m->items[i].label = NULL;
}
if (m->items[i].value)
{
free(m->items[i].value);
m->items[i].value = NULL;
}
}
m->itemCount = 0;
}
void printMenu(Menu* m)
{
clearScreen(&bottomScreen);
if (!m) return;
//header
iprintf("\x1B[42m"); //green
iprintf("%.30s\n\n", m->header);
iprintf("\x1B[47m"); //white
if (m->itemCount <= 0)
{
iprintf("Back - [B]\n");
return;
}
//items
for (int i = 0; i < m->itemCount; i++)
{
if (m->items[i].label)
{
if(!m->items[i].enabled)
iprintf("\x1B[37m"); //gray
if (m->items[i].directory)
iprintf(" [%.26s]\n", m->items[i].label);
else
iprintf(" %.28s\n", m->items[i].label);
if(!m->items[i].enabled)
iprintf("\x1B[47m"); //white
}
else
iprintf(" \n");
}
//cursor
iprintf("\x1b[%d;0H>", 2 + m->cursor);
//scroll arrows
if (m->page > 0)
iprintf("\x1b[2;31H^");
if (m->nextPage)
iprintf("\x1b[21;31Hv");
}
static void _moveCursor(Menu* m, int dir)
{
if (m->changePage != 0)
return;
m->cursor += sign(dir);
if (m->cursor < 0)
{
if (m->page <= 0)
m->cursor = 0;
else
{
m->changePage = -1;
m->cursor = ITEMS_PER_PAGE - 1;
}
}
else if (m->cursor > m->itemCount-1)
{
if (m->nextPage && m->cursor >= ITEMS_PER_PAGE)
{
m->changePage = 1;
m->cursor = 0;
}
else
{
m->cursor = m->itemCount-1;
}
}
}
bool moveCursor(Menu* m)
{
if (!m) return false;
m->changePage = 0;
int lastCursor = m->cursor;
u32 down = keysDownRepeat();
if (down & KEY_DOWN)
_moveCursor(m, 1);
else if (down & KEY_UP)
_moveCursor(m, -1);
if (down & KEY_RIGHT)
{
repeat(10)
_moveCursor(m, 1);
}
else if (down & KEY_LEFT)
{
repeat(10)
_moveCursor(m, -1);
}
return !(lastCursor == m->cursor);
#include "menu.h"
#include "main.h"
#define sign(X) ( ((X) > 0) - ((X) < 0) )
#define repeat(X) for (int _I_ = 0; _I_ < (X); _I_++)
Menu* newMenu()
{
Menu* m = (Menu*)malloc(sizeof(Menu));
m->cursor = 0;
m->page = 0;
m->itemCount = 0;
m->nextPage = false;
m->changePage = 0;
m->header[0] = '\0';
for (int i = 0; i < ITEMS_PER_PAGE; i++)
{
m->items[i].directory = false;
m->items[i].label = NULL;
m->items[i].value = NULL;
}
return m;
}
void freeMenu(Menu* m)
{
if (!m) return;
clearMenu(m);
free(m);
m = NULL;
}
void addMenuItem(Menu* m, char const* label, char const* value, bool enabled, bool directory)
{
if (!m) return;
int i = m->itemCount;
if (i >= ITEMS_PER_PAGE) return;
m->items[i].directory = directory;
m->items[i].enabled = enabled;
if (label)
{
m->items[i].label = (char*)malloc(32);
sprintf(m->items[i].label, "%.31s", label);
}
if (value)
{
m->items[i].value = (char*)malloc(strlen(value)+1);
sprintf(m->items[i].value, "%s", value);
}
m->itemCount += 1;
}
static int alphabeticalCompare(const void* a, const void* b)
{
const Item* itemA = (const Item*)a;
const Item* itemB = (const Item*)b;
if (itemA->directory && !itemB->directory)
return -1;
else if (!itemA->directory && itemB->directory)
return 1;
else
return strcasecmp(itemA->label, itemB->label);
}
void sortMenuItems(Menu* m)
{
qsort(m->items, m->itemCount, sizeof(Item), alphabeticalCompare);
}
void setMenuHeader(Menu* m, const char* str)
{
if (!m) return;
if (!str)
{
m->header[0] = '\0';
return;
}
const char* strPtr = str;
if (strlen(strPtr) > 30)
strPtr = str + (strlen(strPtr) - 30);
sprintf(m->header, "%.30s", strPtr);
}
void resetMenu(Menu* m)
{
m->cursor = 0;
m->page = 0;
m->changePage = 0;
m->nextPage = 0;
}
void clearMenu(Menu* m)
{
if (!m) return;
for (int i = 0; i < ITEMS_PER_PAGE; i++)
{
if (m->items[i].label)
{
free(m->items[i].label);
m->items[i].label = NULL;
}
if (m->items[i].value)
{
free(m->items[i].value);
m->items[i].value = NULL;
}
}
m->itemCount = 0;
}
void printMenu(Menu* m)
{
clearScreen(&bottomScreen);
if (!m) return;
//header
iprintf("\x1B[42m"); //green
iprintf("%.30s\n\n", m->header);
iprintf("\x1B[47m"); //white
if (m->itemCount <= 0)
{
iprintf("Back - [B]\n");
return;
}
//items
for (int i = 0; i < m->itemCount; i++)
{
if (m->items[i].label)
{
if(!m->items[i].enabled)
iprintf("\x1B[37m"); //gray
if (m->items[i].directory)
iprintf(" [%.26s]\n", m->items[i].label);
else
iprintf(" %.28s\n", m->items[i].label);
if(!m->items[i].enabled)
iprintf("\x1B[47m"); //white
}
else
iprintf(" \n");
}
//cursor
iprintf("\x1b[%d;0H>", 2 + m->cursor);
//scroll arrows
if (m->page > 0)
iprintf("\x1b[2;31H^");
if (m->nextPage)
iprintf("\x1b[21;31Hv");
}
static void _moveCursor(Menu* m, int dir)
{
if (m->changePage != 0)
return;
m->cursor += sign(dir);
if (m->cursor < 0)
{
if (m->page <= 0)
m->cursor = 0;
else
{
m->changePage = -1;
m->cursor = ITEMS_PER_PAGE - 1;
}
}
else if (m->cursor > m->itemCount-1)
{
if (m->nextPage && m->cursor >= ITEMS_PER_PAGE)
{
m->changePage = 1;
m->cursor = 0;
}
else
{
m->cursor = m->itemCount-1;
}
}
}
bool moveCursor(Menu* m)
{
if (!m) return false;
m->changePage = 0;
int lastCursor = m->cursor;
u32 down = keysDownRepeat();
if (down & KEY_DOWN)
_moveCursor(m, 1);
else if (down & KEY_UP)
_moveCursor(m, -1);
if (down & KEY_RIGHT)
{
repeat(10)
_moveCursor(m, 1);
}
else if (down & KEY_LEFT)
{
repeat(10)
_moveCursor(m, -1);
}
return !(lastCursor == m->cursor);
}

View File

@ -1,46 +1,46 @@
#ifndef MENU_H
#define MENU_H
#include <nds/ndstypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ITEMS_PER_PAGE 20
typedef struct {
bool directory;
bool enabled;
char* label;
char* value;
} Item;
typedef struct {
int cursor;
int page;
int itemCount;
bool nextPage;
int changePage;
char header[32];
Item items[ITEMS_PER_PAGE];
} Menu;
Menu* newMenu();
void freeMenu(Menu* m);
void addMenuItem(Menu* m, char const* label, char const* value, bool enabled, bool directory);
void sortMenuItems(Menu* m);
void setMenuHeader(Menu* m, const char* str);
void resetMenu(Menu* m);
void clearMenu(Menu* m);
void printMenu(Menu* m);
bool moveCursor(Menu* m);
#ifdef __cplusplus
}
#endif
#ifndef MENU_H
#define MENU_H
#include <nds/ndstypes.h>
#ifdef __cplusplus
extern "C" {
#endif
#define ITEMS_PER_PAGE 20
typedef struct {
bool directory;
bool enabled;
char* label;
char* value;
} Item;
typedef struct {
int cursor;
int page;
int itemCount;
bool nextPage;
int changePage;
char header[32];
Item items[ITEMS_PER_PAGE];
} Menu;
Menu* newMenu();
void freeMenu(Menu* m);
void addMenuItem(Menu* m, char const* label, char const* value, bool enabled, bool directory);
void sortMenuItems(Menu* m);
void setMenuHeader(Menu* m, const char* str);
void resetMenu(Menu* m);
void clearMenu(Menu* m);
void printMenu(Menu* m);
bool moveCursor(Menu* m);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,161 +1,161 @@
#include "message.h"
#include "main.h"
void keyWait(u32 key)
{
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
if (keysDown() & key)
break;
}
}
bool choiceBox(const char* message)
{
const int choiceRow = 10;
int cursor = 0;
clearScreen(&bottomScreen);
iprintf("\x1B[33m"); //yellow
iprintf("%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("\x1b[%d;0H\tYes\n\tNo\n", choiceRow);
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
//Clear cursor
iprintf("\x1b[%d;0H ", choiceRow + cursor);
if (keysDown() & (KEY_UP | KEY_DOWN))
cursor = !cursor;
//Print cursor
iprintf("\x1b[%d;0H>", choiceRow + cursor);
if (keysDown() & (KEY_A | KEY_START))
break;
if (keysDown() & KEY_B)
{
cursor = 1;
break;
}
}
scanKeys();
return (cursor == 0)? YES: NO;
}
bool choicePrint(const char* message)
{
bool choice = NO;
iprintf("\x1B[33m"); //yellow
iprintf("\n%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("Yes - [A]\nNo - [B]\n");
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
if (keysDown() & KEY_A)
{
choice = YES;
break;
}
else if (keysDown() & KEY_B)
{
choice = NO;
break;
}
}
scanKeys();
return choice;
}
const static u16 keys[] = {KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_LEFT, KEY_A, KEY_B, KEY_X, KEY_Y};
const static char *keysLabels[] = {"\x18", "\x19", "\x1A", "\x1B", "<A>", "<B>", "<X>", "<Y>"};
bool randomConfirmBox(const char* message)
{
const int choiceRow = 10;
int sequencePosition = 0;
u8 sequence[8];
for (int i = 0; i < sizeof(sequence); i++)
{
sequence[i] = rand() % (sizeof(keys) / sizeof(keys[0]));
}
clearScreen(&bottomScreen);
iprintf("\x1B[43m"); //yellow
iprintf("%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("\n<START> cancel\n");
while (!programEnd && sequencePosition < sizeof(sequence))
{
swiWaitForVBlank();
scanKeys();
//Print sequence
iprintf("\x1b[%d;0H", choiceRow);
for (int i = 0; i < sizeof(sequence); i++)
{
iprintf("\x1B[%0om", i < sequencePosition ? 032 : 047);
iprintf("%s ", keysLabels[sequence[i]]);
}
if (keysDown() & (KEY_UP | KEY_DOWN | KEY_RIGHT | KEY_LEFT | KEY_A | KEY_B | KEY_X | KEY_Y))
{
if (keysDown() & keys[sequence[sequencePosition]])
sequencePosition++;
else
sequencePosition = 0;
}
if (keysDown() & KEY_START)
{
sequencePosition = 0;
break;
}
}
scanKeys();
return sequencePosition == sizeof(sequence);
}
void messageBox(const char* message)
{
clearScreen(&bottomScreen);
messagePrint(message);
}
void messagePrint(const char* message)
{
iprintf("%s\n", message);
iprintf("\nOkay - [A]\n");
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
if (keysDown() & (KEY_A | KEY_B | KEY_START))
break;
}
scanKeys();
#include "message.h"
#include "main.h"
void keyWait(u32 key)
{
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
if (keysDown() & key)
break;
}
}
bool choiceBox(const char* message)
{
const int choiceRow = 10;
int cursor = 0;
clearScreen(&bottomScreen);
iprintf("\x1B[33m"); //yellow
iprintf("%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("\x1b[%d;0H\tYes\n\tNo\n", choiceRow);
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
//Clear cursor
iprintf("\x1b[%d;0H ", choiceRow + cursor);
if (keysDown() & (KEY_UP | KEY_DOWN))
cursor = !cursor;
//Print cursor
iprintf("\x1b[%d;0H>", choiceRow + cursor);
if (keysDown() & (KEY_A | KEY_START))
break;
if (keysDown() & KEY_B)
{
cursor = 1;
break;
}
}
scanKeys();
return (cursor == 0)? YES: NO;
}
bool choicePrint(const char* message)
{
bool choice = NO;
iprintf("\x1B[33m"); //yellow
iprintf("\n%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("Yes - [A]\nNo - [B]\n");
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
if (keysDown() & KEY_A)
{
choice = YES;
break;
}
else if (keysDown() & KEY_B)
{
choice = NO;
break;
}
}
scanKeys();
return choice;
}
const static u16 keys[] = {KEY_UP, KEY_DOWN, KEY_RIGHT, KEY_LEFT, KEY_A, KEY_B, KEY_X, KEY_Y};
const static char *keysLabels[] = {"\x18", "\x19", "\x1A", "\x1B", "<A>", "<B>", "<X>", "<Y>"};
bool randomConfirmBox(const char* message)
{
const int choiceRow = 10;
int sequencePosition = 0;
u8 sequence[8];
for (int i = 0; i < sizeof(sequence); i++)
{
sequence[i] = rand() % (sizeof(keys) / sizeof(keys[0]));
}
clearScreen(&bottomScreen);
iprintf("\x1B[43m"); //yellow
iprintf("%s\n", message);
iprintf("\x1B[47m"); //white
iprintf("\n<START> cancel\n");
while (!programEnd && sequencePosition < sizeof(sequence))
{
swiWaitForVBlank();
scanKeys();
//Print sequence
iprintf("\x1b[%d;0H", choiceRow);
for (int i = 0; i < sizeof(sequence); i++)
{
iprintf("\x1B[%0om", i < sequencePosition ? 032 : 047);
iprintf("%s ", keysLabels[sequence[i]]);
}
if (keysDown() & (KEY_UP | KEY_DOWN | KEY_RIGHT | KEY_LEFT | KEY_A | KEY_B | KEY_X | KEY_Y))
{
if (keysDown() & keys[sequence[sequencePosition]])
sequencePosition++;
else
sequencePosition = 0;
}
if (keysDown() & KEY_START)
{
sequencePosition = 0;
break;
}
}
scanKeys();
return sequencePosition == sizeof(sequence);
}
void messageBox(const char* message)
{
clearScreen(&bottomScreen);
messagePrint(message);
}
void messagePrint(const char* message)
{
iprintf("%s\n", message);
iprintf("\nOkay - [A]\n");
while (!programEnd)
{
swiWaitForVBlank();
scanKeys();
if (keysDown() & (KEY_A | KEY_B | KEY_START))
break;
}
scanKeys();
}

View File

@ -1,26 +1,26 @@
#ifndef MESSAGE_H
#define MESSAGE_H
#include <nds/ndstypes.h>
#ifdef __cplusplus
extern "C" {
#endif
enum {
YES = true,
NO = false
};
void keyWait(u32 key);
bool choiceBox(const char* message);
bool choicePrint(const char* message);
bool randomConfirmBox(const char* message);
void messageBox(const char* message);
void messagePrint(const char* message);
#ifdef __cplusplus
}
#endif
#ifndef MESSAGE_H
#define MESSAGE_H
#include <nds/ndstypes.h>
#ifdef __cplusplus
extern "C" {
#endif
enum {
YES = true,
NO = false
};
void keyWait(u32 key);
bool choiceBox(const char* message);
bool choicePrint(const char* message);
bool randomConfirmBox(const char* message);
void messageBox(const char* message);
void messagePrint(const char* message);
#ifdef __cplusplus
}
#endif
#endif

View File

@ -1,257 +1,257 @@
#include "storage.h"
#include "main.h"
#include "message.h"
#include <errno.h>
#include <nds/sha1.h>
#include <dirent.h>
#define TITLE_LIMIT 39
//progress bar
static int lastBars = 0;
static void printProgressBar(float percent)
{
if (percent < 0.f) percent = 0.f;
if (percent > 1.f) percent = 1.f;
int bars = (int)(30.f * percent);
//skip redundant prints
if (bars != lastBars)
{
consoleSelect(&topScreen);
iprintf("\x1B[42m"); //green
//Print frame
if (lastBars <= 0)
{
iprintf("\x1b[23;0H[");
iprintf("\x1b[23;31H]");
}
//Print bars
if (bars > 0)
{
for (int i = 0; i < bars; i++)
iprintf("\x1b[23;%dH|", 1 + i);
}
lastBars = bars;
iprintf("\x1B[47m"); //white
}
}
static void clearProgressBar()
{
lastBars = 0;
consoleSelect(&topScreen);
iprintf("\x1b[23;0H ");
}
//files
bool fileExists(char const* path)
{
return access(path, F_OK) == 0;
}
int copyFile(char const* src, char const* dst)
{
if (!src) return 1;
unsigned long long size = getFileSizePath(src);
return copyFilePart(src, 0, size, dst);
}
int copyFilePart(char const* src, u32 offset, u32 size, char const* dst)
{
if (!src) return 1;
if (!dst) return 2;
FILE* fin = fopen(src, "rb");
if (!fin)
{
fclose(fin);
return 3;
}
else
{
if (fileExists(dst))
remove(dst);
FILE* fout = fopen(dst, "wb");
if (!fout)
{
fclose(fin);
fclose(fout);
return 4;
}
else
{
fseek(fin, offset, SEEK_SET);
consoleSelect(&topScreen);
int bytesRead;
unsigned long long totalBytesRead = 0;
#define BUFF_SIZE 128 //Arbitrary. A value too large freezes the ds.
char* buffer = (char*)malloc(BUFF_SIZE);
while (!programEnd)
{
unsigned int toRead = BUFF_SIZE;
if (size - totalBytesRead < BUFF_SIZE)
toRead = size - totalBytesRead;
bytesRead = fread(buffer, 1, toRead, fin);
fwrite(buffer, bytesRead, 1, fout);
totalBytesRead += bytesRead;
printProgressBar( ((float)totalBytesRead / (float)size) );
if (bytesRead != BUFF_SIZE)
break;
}
clearProgressBar();
consoleSelect(&bottomScreen);
free(buffer);
}
fclose(fout);
}
fclose(fin);
return 0;
}
unsigned long long getFileSize(FILE* f)
{
if (!f) return 0;
fseek(f, 0, SEEK_END);
unsigned long long size = ftell(f);
fseek(f, 0, SEEK_SET);
return size;
}
unsigned long long getFileSizePath(char const* path)
{
if (!path) return 0;
FILE* f = fopen(path, "rb");
unsigned long long size = getFileSize(f);
fclose(f);
return size;
}
bool toggleFileReadOnly(const char* path, bool readOnly)
{
int fatAttributes = FAT_getAttr(path);
if (readOnly)
fatAttributes |= ATTR_READONLY;
else
fatAttributes &= ~ATTR_READONLY;
return FAT_setAttr(path, fatAttributes) == 0;
}
bool writeToFile(FILE* fd, const char* buffer, size_t size)
{
int toWrite = size;
size_t written;
//write the first 520 bytes as 0, as that's the size of a tmd, but it can be whatever content
while (toWrite > 0 && (written = fwrite(buffer, sizeof(char), toWrite, fd)) > 0)
{
toWrite -= written;
buffer += written;
}
return toWrite == 0;
}
bool calculateFileSha1(FILE* f, void* digest)
{
fseek(f, 0, SEEK_SET);
swiSHA1context_t ctx;
ctx.sha_block = 0; //this is weird but it has to be done
swiSHA1Init(&ctx);
char buffer[512];
size_t n = 0;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), f)) > 0)
{
swiSHA1Update(&ctx, buffer, n);
}
if (ferror(f) || !feof(f))
{
return false;
}
swiSHA1Final(digest, &ctx);
return true;
}
bool calculateFileSha1Path(const char* path, void* digest)
{
FILE* targetFile = fopen(path, "rb");
if (!targetFile)
{
return false;
}
bool res = calculateFileSha1(targetFile, digest);
fclose(targetFile);
return res;
}
bool safeCreateDir(const char* path)
{
if (((mkdir(path, 0777) == 0) || errno == EEXIST))
return true;
char errorStr[512];
sprintf(errorStr, "\x1B[31mError:\x1B[33m Failed to create directory (%s)\n", path);
messageBox(errorStr);
return false;
}
bool removeIfExists(const char* path)
{
return remove(path) == 0 || errno == ENOENT;
}
// Filesystem type
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
//trimmed down PARTITION struct from libfat internals
typedef struct {
const void* disc;
void* cache;
// Info about the partition
FS_TYPE filesysType;
uint64_t totalSize;
sec_t rootDirStart;
uint32_t rootDirCluster;
uint32_t numberOfSectors;
sec_t dataStart;
uint32_t bytesPerSector;
uint32_t sectorsPerCluster;
uint32_t bytesPerCluster;
uint32_t fsInfoSector;
} PARTITION;
extern PARTITION* _FAT_partition_getPartitionFromPath(const char* path);
u32 getClusterSizeForPartition(const char* path)
{
PARTITION* p = _FAT_partition_getPartitionFromPath(path);
if(!p)
return 0;
return p->bytesPerCluster;
}
#include "storage.h"
#include "main.h"
#include "message.h"
#include <errno.h>
#include <nds/sha1.h>
#include <dirent.h>
#define TITLE_LIMIT 39
//progress bar
static int lastBars = 0;
static void printProgressBar(float percent)
{
if (percent < 0.f) percent = 0.f;
if (percent > 1.f) percent = 1.f;
int bars = (int)(30.f * percent);
//skip redundant prints
if (bars != lastBars)
{
consoleSelect(&topScreen);
iprintf("\x1B[42m"); //green
//Print frame
if (lastBars <= 0)
{
iprintf("\x1b[23;0H[");
iprintf("\x1b[23;31H]");
}
//Print bars
if (bars > 0)
{
for (int i = 0; i < bars; i++)
iprintf("\x1b[23;%dH|", 1 + i);
}
lastBars = bars;
iprintf("\x1B[47m"); //white
}
}
static void clearProgressBar()
{
lastBars = 0;
consoleSelect(&topScreen);
iprintf("\x1b[23;0H ");
}
//files
bool fileExists(char const* path)
{
return access(path, F_OK) == 0;
}
int copyFile(char const* src, char const* dst)
{
if (!src) return 1;
unsigned long long size = getFileSizePath(src);
return copyFilePart(src, 0, size, dst);
}
int copyFilePart(char const* src, u32 offset, u32 size, char const* dst)
{
if (!src) return 1;
if (!dst) return 2;
FILE* fin = fopen(src, "rb");
if (!fin)
{
fclose(fin);
return 3;
}
else
{
if (fileExists(dst))
remove(dst);
FILE* fout = fopen(dst, "wb");
if (!fout)
{
fclose(fin);
fclose(fout);
return 4;
}
else
{
fseek(fin, offset, SEEK_SET);
consoleSelect(&topScreen);
int bytesRead;
unsigned long long totalBytesRead = 0;
#define BUFF_SIZE 128 //Arbitrary. A value too large freezes the ds.
char* buffer = (char*)malloc(BUFF_SIZE);
while (!programEnd)
{
unsigned int toRead = BUFF_SIZE;
if (size - totalBytesRead < BUFF_SIZE)
toRead = size - totalBytesRead;
bytesRead = fread(buffer, 1, toRead, fin);
fwrite(buffer, bytesRead, 1, fout);
totalBytesRead += bytesRead;
printProgressBar( ((float)totalBytesRead / (float)size) );
if (bytesRead != BUFF_SIZE)
break;
}
clearProgressBar();
consoleSelect(&bottomScreen);
free(buffer);
}
fclose(fout);
}
fclose(fin);
return 0;
}
unsigned long long getFileSize(FILE* f)
{
if (!f) return 0;
fseek(f, 0, SEEK_END);
unsigned long long size = ftell(f);
fseek(f, 0, SEEK_SET);
return size;
}
unsigned long long getFileSizePath(char const* path)
{
if (!path) return 0;
FILE* f = fopen(path, "rb");
unsigned long long size = getFileSize(f);
fclose(f);
return size;
}
bool toggleFileReadOnly(const char* path, bool readOnly)
{
int fatAttributes = FAT_getAttr(path);
if (readOnly)
fatAttributes |= ATTR_READONLY;
else
fatAttributes &= ~ATTR_READONLY;
return FAT_setAttr(path, fatAttributes) == 0;
}
bool writeToFile(FILE* fd, const char* buffer, size_t size)
{
int toWrite = size;
size_t written;
//write the first 520 bytes as 0, as that's the size of a tmd, but it can be whatever content
while (toWrite > 0 && (written = fwrite(buffer, sizeof(char), toWrite, fd)) > 0)
{
toWrite -= written;
buffer += written;
}
return toWrite == 0;
}
bool calculateFileSha1(FILE* f, void* digest)
{
fseek(f, 0, SEEK_SET);
swiSHA1context_t ctx;
ctx.sha_block = 0; //this is weird but it has to be done
swiSHA1Init(&ctx);
char buffer[512];
size_t n = 0;
while ((n = fread(buffer, sizeof(char), sizeof(buffer), f)) > 0)
{
swiSHA1Update(&ctx, buffer, n);
}
if (ferror(f) || !feof(f))
{
return false;
}
swiSHA1Final(digest, &ctx);
return true;
}
bool calculateFileSha1Path(const char* path, void* digest)
{
FILE* targetFile = fopen(path, "rb");
if (!targetFile)
{
return false;
}
bool res = calculateFileSha1(targetFile, digest);
fclose(targetFile);
return res;
}
bool safeCreateDir(const char* path)
{
if (((mkdir(path, 0777) == 0) || errno == EEXIST))
return true;
char errorStr[512];
sprintf(errorStr, "\x1B[31mError:\x1B[33m Failed to create directory (%s)\n", path);
messageBox(errorStr);
return false;
}
bool removeIfExists(const char* path)
{
return remove(path) == 0 || errno == ENOENT;
}
// Filesystem type
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
//trimmed down PARTITION struct from libfat internals
typedef struct {
const void* disc;
void* cache;
// Info about the partition
FS_TYPE filesysType;
uint64_t totalSize;
sec_t rootDirStart;
uint32_t rootDirCluster;
uint32_t numberOfSectors;
sec_t dataStart;
uint32_t bytesPerSector;
uint32_t sectorsPerCluster;
uint32_t bytesPerCluster;
uint32_t fsInfoSector;
} PARTITION;
extern PARTITION* _FAT_partition_getPartitionFromPath(const char* path);
u32 getClusterSizeForPartition(const char* path)
{
PARTITION* p = _FAT_partition_getPartitionFromPath(path);
if(!p)
return 0;
return p->bytesPerCluster;
}

View File

@ -1,34 +1,34 @@
#ifndef STORAGE_H
#define STORAGE_H
#include <nds/ndstypes.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
//Files
bool fileExists(char const* path);
int copyFile(char const* src, char const* dst);
int copyFilePart(char const* src, u32 offset, u32 size, char const* dst);
unsigned long long getFileSize(FILE* f);
unsigned long long getFileSizePath(char const* path);
bool toggleFileReadOnly(const char* path, bool readOnly);
bool writeToFile(FILE* fd, const char* buffer, size_t size);
bool calculateFileSha1(FILE* f, void* digest);
bool calculateFileSha1Path(const char* path, void* digest);
//Directories
bool safeCreateDir(const char* path);
//Files and directories
bool removeIfExists(const char* path);
u32 getClusterSizeForPartition(const char* path);
#ifdef __cplusplus
}
#endif
#ifndef STORAGE_H
#define STORAGE_H
#include <nds/ndstypes.h>
#include <stdio.h>
#ifdef __cplusplus
extern "C" {
#endif
//Files
bool fileExists(char const* path);
int copyFile(char const* src, char const* dst);
int copyFilePart(char const* src, u32 offset, u32 size, char const* dst);
unsigned long long getFileSize(FILE* f);
unsigned long long getFileSizePath(char const* path);
bool toggleFileReadOnly(const char* path, bool readOnly);
bool writeToFile(FILE* fd, const char* buffer, size_t size);
bool calculateFileSha1(FILE* f, void* digest);
bool calculateFileSha1Path(const char* path, void* digest);
//Directories
bool safeCreateDir(const char* path);
//Files and directories
bool removeIfExists(const char* path);
u32 getClusterSizeForPartition(const char* path);
#ifdef __cplusplus
}
#endif
#endif