From d010f2858bc2c852f81cca3ac2bc3537c96ecd1a Mon Sep 17 00:00:00 2001 From: Gabriel Marcano Date: Mon, 24 Aug 2020 21:27:19 -0700 Subject: [PATCH] Remove trailing white space - Removed trailing whitespace from all source code files (.c, .h. and .s) and the README.md --- README.md | 2 +- arm11/source/arm/gic.h | 2 +- arm9/source/common/rtc.c | 8 +- arm9/source/common/swkbd.c | 10 +- arm9/source/common/timer.c | 4 +- arm9/source/common/touchcal.c | 6 +- arm9/source/common/ui.c | 26 +- arm9/source/common/utf.c | 4 +- arm9/source/crypto/aes.c | 12 +- arm9/source/crypto/crc16.c | 4 +- arm9/source/crypto/crc32.c | 4 +- arm9/source/crypto/keydb.c | 54 +-- arm9/source/crypto/keydb.h | 4 +- arm9/source/crypto/sha.c | 4 +- arm9/source/fatfs/diskio.c | 20 +- arm9/source/filesys/fatmbr.c | 4 +- arm9/source/filesys/fatmbr.h | 4 +- arm9/source/filesys/filetype.c | 4 +- arm9/source/filesys/fsdrive.c | 22 +- arm9/source/filesys/fsdrive.h | 2 +- arm9/source/filesys/fsgame.c | 6 +- arm9/source/filesys/fsinit.c | 2 +- arm9/source/filesys/fsinit.h | 4 +- arm9/source/filesys/fsperm.c | 22 +- arm9/source/filesys/fsutil.c | 186 ++++----- arm9/source/filesys/image.c | 2 +- arm9/source/filesys/sddata.c | 56 +-- arm9/source/filesys/support.c | 12 +- arm9/source/filesys/vff.c | 52 +-- arm9/source/game/bdri.c | 274 ++++++------- arm9/source/game/boss.c | 20 +- arm9/source/game/boss.h | 4 +- arm9/source/game/cia.c | 14 +- arm9/source/game/codelzss.c | 108 ++--- arm9/source/game/disadiff.c | 120 +++--- arm9/source/game/firm.c | 46 +-- arm9/source/game/gba.c | 32 +- arm9/source/game/gba.h | 12 +- arm9/source/game/ips.c | 24 +- arm9/source/game/ncch.c | 80 ++-- arm9/source/game/ncchinfo.c | 14 +- arm9/source/game/ncsd.c | 12 +- arm9/source/game/nds.c | 22 +- arm9/source/game/nds.h | 2 +- arm9/source/game/romfs.c | 20 +- arm9/source/game/tad.c | 8 +- arm9/source/game/ticket.c | 16 +- arm9/source/game/ticketdb.c | 30 +- arm9/source/game/tie.c | 8 +- arm9/source/game/tmd.c | 16 +- arm9/source/gamecart/card_spi.c | 116 +++--- arm9/source/gamecart/card_spi.h | 2 +- arm9/source/gamecart/command_ntr.c | 4 +- arm9/source/gamecart/gamecart.c | 20 +- arm9/source/gamecart/secure_ntr.c | 4 +- arm9/source/godmode.c | 286 ++++++------- arm9/source/nand/essentials.h | 2 +- arm9/source/nand/nand.c | 92 ++--- arm9/source/qrcodegen/qrcodegen.c | 72 ++-- arm9/source/qrcodegen/qrcodegen.h | 46 +-- arm9/source/system/memmap.h | 2 +- arm9/source/system/spiflash.c | 2 +- arm9/source/system/tar.c | 30 +- arm9/source/system/vram0.h | 6 +- arm9/source/utils/ctrtransfer.c | 18 +- arm9/source/utils/gameutil.c | 632 ++++++++++++++--------------- arm9/source/utils/keydbutil.c | 46 +-- arm9/source/utils/nandcmac.c | 60 +-- arm9/source/utils/nandutil.c | 152 +++---- arm9/source/utils/paint9.c | 2 +- arm9/source/utils/scripting.c | 280 ++++++------- arm9/source/utils/sysinfo.c | 16 +- arm9/source/virtual/vbdri.c | 76 ++-- arm9/source/virtual/vcart.c | 6 +- arm9/source/virtual/vdisadiff.c | 84 ++-- arm9/source/virtual/vgame.c | 186 ++++----- arm9/source/virtual/virtual.c | 28 +- arm9/source/virtual/vkeydb.c | 16 +- arm9/source/virtual/vmem.c | 18 +- arm9/source/virtual/vnand.c | 10 +- arm9/source/virtual/vvram.c | 38 +- 81 files changed, 1888 insertions(+), 1888 deletions(-) diff --git a/README.md b/README.md index b667232..3c6c603 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ With the possibilites GodMode9 provides, not everything may be obvious at first * __Hexview and hexedit any file__: Press the A button on a file and select `Show in Hexeditor`. A button again enables edit mode, hold the A button and press arrow buttons to edit bytes. You will get an additional confirmation prompt to take over changes. Take note that for certain files, write permissions can't be enabled. * __View text files in a text viewer__: Press the A button on a file and select `Show in Textviewer` (only shows up for actual text files). You can enable wordwrapped mode via R+Y, and navigate around the file via R+X and the dpad. * __Chainload FIRM payloads__: Press the A button on a FIRM file, select `FIRM options` -> `Boot FIRM`. Keep in mind you should not run FIRMs from dubious sources and that the write permissions system is no longer in place after booting a payload. -* __Chainload FIRM payloads from a neat menu__: The `payloads` menu is found inside the HOME button menu. It provides any FIRM found in `0:/gm9/payloads` for quick chainloading. +* __Chainload FIRM payloads from a neat menu__: The `payloads` menu is found inside the HOME button menu. It provides any FIRM found in `0:/gm9/payloads` for quick chainloading. * __Inject a file to another file__: Put exactly one file (the file to be injected from) into the clipboard (via the Y button). Press A on the file to be injected to. There will be an option to inject the first file into it. ### Scripting functionality diff --git a/arm11/source/arm/gic.h b/arm11/source/arm/gic.h index 7f1593a..70c6777 100644 --- a/arm11/source/arm/gic.h +++ b/arm11/source/arm/gic.h @@ -31,7 +31,7 @@ enum { GIC_RISINGEDGE_1N = 3 // With the 1-N model, an interrupt that is taken on any CPU clears the Pending - // status on all CPUs. + // status on all CPUs. // With the N-N model, all CPUs receive the interrupt independently. The Pending // status is cleared only for the CPU that takes it, not for the other CPUs }; diff --git a/arm9/source/common/rtc.c b/arm9/source/common/rtc.c index ecc3911..03b9a39 100644 --- a/arm9/source/common/rtc.c +++ b/arm9/source/common/rtc.c @@ -7,23 +7,23 @@ bool is_valid_dstime(DsTime* dstime) { (DSTIMEGET(dstime, bcd_m) >= 60) || (DSTIMEGET(dstime, bcd_s) >= 60)) return false; - + // check the date... u32 year = 2000 + DSTIMEGET(dstime, bcd_Y); u32 month = DSTIMEGET(dstime, bcd_M); u32 day = DSTIMEGET(dstime, bcd_D); - + // date: year & month if ((year >= 2100) || (month == 0) || (month > 12)) return false; - + // date: day // see: https://github.com/devkitPro/libnds/blob/9678bf09389cb1fcdc99dfa0357ec0cbe51dd0b7/source/arm7/clock.c#L224-L262 u32 months_lastday[1+12] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; u32 leap = (((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)) ? 1 : 0; u32 days_in_month = months_lastday[month] + ((month == 2) ? leap : 0); if (day > days_in_month) return false; - + return true; } diff --git a/arm9/source/common/swkbd.c b/arm9/source/common/swkbd.c index 5ef3b36..4fdfec2 100644 --- a/arm9/source/common/swkbd.c +++ b/arm9/source/common/swkbd.c @@ -73,7 +73,7 @@ static bool BuildKeyboard(TouchBox* swkbd, const char* keys, const u8* layout) { static void DrawKey(const TouchBox* key, const bool pressed, const u32 uppercase) { const char* keystrs[] = { SWKBD_KEYSTR }; - const u32 color = (pressed) ? COLOR_SWKBD_PRESSED : + const u32 color = (pressed) ? COLOR_SWKBD_PRESSED : (key->id == KEY_ENTER) ? COLOR_SWKBD_ENTER : ((key->id == KEY_CAPS) && (uppercase > 1)) ? COLOR_SWKBD_CAPS : COLOR_SWKBD_NORMAL; @@ -125,12 +125,12 @@ static void DrawTextBox(const TouchBox* txtbox, const char* inputstr, const u32 const u32 input_shown = (txtbox->w / FONT_WIDTH_EXT) - 2; const u32 inputstr_size = strlen(inputstr); // we rely on a zero terminated string const u16 x = txtbox->x; - const u16 y = txtbox->y; - + const u16 y = txtbox->y; + // fix scroll if (cursor < *scroll) *scroll = cursor; else if (cursor - *scroll > input_shown) *scroll = cursor - input_shown; - + // draw input string DrawStringF(BOT_SCREEN, x, y, COLOR_STD_FONT, COLOR_STD_BG, "%c%-*.*s%-*.*s%c", (*scroll) ? '<' : '|', @@ -142,7 +142,7 @@ static void DrawTextBox(const TouchBox* txtbox, const char* inputstr, const u32 "", (inputstr_size - (s32) *scroll > input_shown) ? '>' : '|' ); - + // draw cursor DrawStringF(BOT_SCREEN, x-(FONT_WIDTH_EXT/2), y+10, COLOR_STD_FONT, COLOR_STD_BG, "%-*.*s^%-*.*s", 1 + cursor - *scroll, diff --git a/arm9/source/common/timer.c b/arm9/source/common/timer.c index 79f67d6..3cec117 100644 --- a/arm9/source/common/timer.c +++ b/arm9/source/common/timer.c @@ -7,7 +7,7 @@ u64 timer_start( void ) { if (!(*TIMER_CNT0 & *TIMER_CNT1 & *TIMER_CNT2 & *TIMER_CNT3 & TIMER_ACTIVE) || !(*TIMER_CNT1 & *TIMER_CNT2 & *TIMER_CNT3 & TIMER_COUNT_UP)) timer_init = true; - + if (timer_init) { // deactivate, then reset timers *TIMER_CNT0 = 0; @@ -17,7 +17,7 @@ u64 timer_start( void ) { // start timers *TIMER_CNT0 = TIMER_ACTIVE; *TIMER_CNT1 = *TIMER_CNT2 = *TIMER_CNT3 = TIMER_ACTIVE | TIMER_COUNT_UP; - + // timer initialized timer_init = false; } diff --git a/arm9/source/common/touchcal.c b/arm9/source/common/touchcal.c index 91d0d66..f1e16c5 100644 --- a/arm9/source/common/touchcal.c +++ b/arm9/source/common/touchcal.c @@ -89,7 +89,7 @@ bool CalibrateTouchFromSupportFile(void) { size_t size = LoadSupportFile(TOUCH_CALIB_FILENAME, calibrations, sizeof(calibrations)); u32 n_dots = size / sizeof(HID_CalibrationData); - is_calibrated = (n_dots == 0) ? false : + is_calibrated = (n_dots == 0) ? false : HID_SetCalibrationData(calibrations, n_dots, SCREEN_WIDTH_BOT, SCREEN_HEIGHT); return is_calibrated; } @@ -99,11 +99,11 @@ bool CalibrateTouchFromFlash(void) { // set calibration defaults SetCalibrationDefaults(); - + // check SPIflash status if (!spiflash_get_status()) return false; - + // check NVRAM console ID u32 console_id = 0; if (!spiflash_read(0x001C, 4, (u8*)&console_id)) diff --git a/arm9/source/common/ui.c b/arm9/source/common/ui.c index 36111aa..be7d5ed 100644 --- a/arm9/source/common/ui.c +++ b/arm9/source/common/ui.c @@ -19,7 +19,7 @@ #define STRBUF_SIZE 512 // maximum size of the string buffer #define FONT_MAX_WIDTH 8 #define FONT_MAX_HEIGHT 10 -#define PROGRESS_REFRESH_RATE 30 // the progress bar is only allowed to draw to screen every X milliseconds +#define PROGRESS_REFRESH_RATE 30 // the progress bar is only allowed to draw to screen every X milliseconds static u32 font_width = 0; static u32 font_height = 0; @@ -247,7 +247,7 @@ void DrawString(u16 *screen, const char *str, int x, int y, u32 color, u32 bgcol size_t len = (strlen(str) > max_len) ? max_len : strlen(str); for (size_t i = 0; i < len; i++) { - char c = (char) (fix_utf8 && str[i] >= 0x80) ? '?' : str[i]; + char c = (char) (fix_utf8 && str[i] >= 0x80) ? '?' : str[i]; DrawCharacter(screen, c, x + i * font_width, y, color, bgcolor); } } @@ -445,17 +445,17 @@ void ShowIconString(u16* icon, int w, int h, const char *format, ...) bool ShowPrompt(bool ask, const char *format, ...) { bool ret = true; - + char str[STRBUF_SIZE]; va_list va; va_start(va, format); vsnprintf(str, STRBUF_SIZE, format, va); va_end(va); - + ClearScreenF(true, false, COLOR_STD_BG); DrawStringCenter(MAIN_SCREEN, COLOR_STD_FONT, COLOR_STD_BG, "%s\n \n%s", str, (ask) ? "( yes, no)" : "( to continue)"); - + while (true) { u32 pad_state = InputWait(0); if (pad_state & BUTTON_A) break; @@ -464,9 +464,9 @@ bool ShowPrompt(bool ask, const char *format, ...) break; } } - + ClearScreenF(true, false, COLOR_STD_BG); - + return ret; } @@ -661,7 +661,7 @@ u32 ShowFileScrollPrompt(u32 n, const DirEntry** options, bool hide_ext, const c DrawStringF(MAIN_SCREEN, x, yopt + ((line_height+2)*(i-scroll)), (sel == (int)i) ? COLOR_STD_FONT : COLOR_ENTRY(options[i]), COLOR_STD_BG, "%2.2s %s", (sel == (int)i) ? "->" : "", content_str); - + DrawStringF(MAIN_SCREEN, x + item_width - font_width * 11, yopt + ((line_height+2)*(i-scroll)), (sel == (int)i) ? COLOR_STD_FONT : COLOR_ENTRY(options[i]), COLOR_STD_BG, "%10.10s", (options[i]->type == T_DIR) ? "(dir)" : (options[i]->type == T_DOTDOT) ? "(..)" : bytestr); @@ -768,7 +768,7 @@ bool ShowInputPrompt(char* inputstr, u32 max_size, u32 resize, const char* alpha if (str_width < (24 * font_width)) str_width = 24 * font_width; x = (str_width >= SCREEN_WIDTH_MAIN) ? 0 : (SCREEN_WIDTH_MAIN - str_width) / 2; y = (str_height >= SCREEN_HEIGHT) ? 0 : (SCREEN_HEIGHT - str_height) / 2; - + ClearScreenF(true, false, COLOR_STD_BG); DrawStringF(MAIN_SCREEN, x, y, COLOR_STD_FONT, COLOR_STD_BG, "%s", str); DrawStringF(MAIN_SCREEN, x + 8, y + str_height - 40, COLOR_STD_FONT, COLOR_STD_BG, @@ -901,7 +901,7 @@ bool ShowStringPrompt(char* inputstr, u32 max_size, const char *format, ...) { ret = ShowInputPrompt(inputstr, max_size, 1, alphabet, format, va); va_end(va); - return ret; + return ret; } u64 ShowHexPrompt(u64 start_val, u32 n_digits, const char *format, ...) { @@ -919,7 +919,7 @@ u64 ShowHexPrompt(u64 start_val, u32 n_digits, const char *format, ...) { } else ret = (u64) -1; va_end(va); - return ret; + return ret; } u64 ShowNumberPrompt(u64 start_val, const char *format, ...) { @@ -936,7 +936,7 @@ u64 ShowNumberPrompt(u64 start_val, const char *format, ...) { } else ret = (u64) -1; va_end(va); - return ret; + return ret; } bool ShowDataPrompt(u8* data, u32* size, const char *format, ...) { @@ -965,7 +965,7 @@ bool ShowDataPrompt(u8* data, u32* size, const char *format, ...) { } va_end(va); - return ret; + return ret; } diff --git a/arm9/source/common/utf.c b/arm9/source/common/utf.c index 12d8a66..dd7fad7 100644 --- a/arm9/source/common/utf.c +++ b/arm9/source/common/utf.c @@ -189,7 +189,7 @@ int utf16_to_utf8(u8 *out, const u16 *in, int len_out, int len_in) units = decode_utf16(&code, in); if(units == -1) return -1; - + if (len_in >= units) len_in -= units; else return -1; @@ -238,7 +238,7 @@ int utf8_to_utf16(u16 *out, const u8 *in, int len_out, int len_in) units = decode_utf8(&code, in); if(units == -1) return -1; - + if (len_in >= units) len_in -= units; else return -1; diff --git a/arm9/source/crypto/aes.c b/arm9/source/crypto/aes.c index 91bdd5a..a9b28ae 100644 --- a/arm9/source/crypto/aes.c +++ b/arm9/source/crypto/aes.c @@ -213,11 +213,11 @@ void ctr_decrypt_byte(void *inbuf, void *outbuf, size_t size, size_t off, uint32 uint8_t *in = inbuf; uint8_t *out = outbuf; uint32_t i; - + for (i=0; i= AES_BLOCK_SIZE) ? @@ -229,7 +229,7 @@ void ctr_decrypt_byte(void *inbuf, void *outbuf, size_t size, size_t off, uint32 *(out++) = temp[i]; bytes_left -= last_byte - off_fix; } - + if (bytes_left >= AES_BLOCK_SIZE) { size_t blocks = bytes_left / AES_BLOCK_SIZE; @@ -238,7 +238,7 @@ void ctr_decrypt_byte(void *inbuf, void *outbuf, size_t size, size_t off, uint32 out += AES_BLOCK_SIZE * blocks; bytes_left -= AES_BLOCK_SIZE * blocks; } - + if (bytes_left) // handle misaligned offset (at end) { for (i=0; i>= 1; len; len--) { u16 curr = *(data++); for (u32 i = 0; i < 4; i++) { @@ -21,6 +21,6 @@ u16 crc16_quick(const void* src, u32 len) { crc ^= tval; } } - + return crc; } diff --git a/arm9/source/crypto/crc32.c b/arm9/source/crypto/crc32.c index 6245ce3..b1e5736 100644 --- a/arm9/source/crypto/crc32.c +++ b/arm9/source/crypto/crc32.c @@ -73,7 +73,7 @@ u32 crc32_calculate_from_file(const char* fileName, u32 offset, u32 length) { return crc32; } fvx_lseek(&inputFile, offset); - + bool ret = true; for (u64 pos = 0; (pos < length) && ret; pos += bufsiz) { UINT read_bytes = min(bufsiz, length - pos); @@ -83,7 +83,7 @@ u32 crc32_calculate_from_file(const char* fileName, u32 offset, u32 length) { ret = false; if (ret) crc32 = crc32_calculate(crc32, buffer, read_bytes); } - + fvx_close(&inputFile); free(buffer); return ~crc32; diff --git a/arm9/source/crypto/keydb.c b/arm9/source/crypto/keydb.c index d55f7b4..c5ea72e 100644 --- a/arm9/source/crypto/keydb.c +++ b/arm9/source/crypto/keydb.c @@ -17,7 +17,7 @@ static u64 keyYState = 0; u32 GetUnitKeysType(void) { static u32 keys_type = KEYS_UNKNOWN; - + if (keys_type == KEYS_UNKNOWN) { static const u8 slot0x2CSampleRetail[16] = { 0xBC, 0xC4, 0x16, 0x2C, 0x2A, 0x06, 0x91, 0xEE, 0x47, 0x18, 0x86, 0xB8, 0xEB, 0x2F, 0xB5, 0x48 }; @@ -35,7 +35,7 @@ u32 GetUnitKeysType(void) keys_type = KEYS_DEVKIT; } } - + return keys_type; } @@ -67,15 +67,15 @@ u32 CheckKeySlot(u32 keyslot, char type) { 0xBC, 0x83, 0x7C, 0xC9, 0x99, 0xC8, 0x80, 0x9E, 0x8A, 0xDE, 0x4A, 0xFA, 0xAA, 0x72, 0x08, 0x28 } } }; u64* state = (type == 'X') ? &keyXState : (type == 'Y') ? &keyYState : (type == 'N') ? &keyState : NULL; - + // just to be safe... if (keyslot >= 0x40) return 1; - + // check if key is already loaded if ((type != 'I') && ((*state >> keyslot) & 1)) return 0; - + // if is not, we may still be able to verify the currently set one (for NCCH keys) for (u32 p = 0; (type == 'X') && (p < sizeof(keyNcchSamples) / sizeof(AesNcchSampleInfo)); p++) { if (keyNcchSamples[p].slot != keyslot) // only for keyslots in the keyNcchSamples table! @@ -93,7 +93,7 @@ u32 CheckKeySlot(u32 keyslot, char type) return 0; } } - + // not set up if getting here return 1; } @@ -102,13 +102,13 @@ u32 CheckKeySlot(u32 keyslot, char type) // to get rid of these, you may replace this function with anything that works for you u32 LoadKeyDb(const char* path_db, AesKeyInfo* keydb, u32 bsize) { UINT fsize = 0; - + if (path_db) { if (fvx_qread (path_db, keydb, 0, bsize, &fsize) != FR_OK) fsize = 0; } else if (fvx_qread ("S:/" KEYDB_NAME, keydb, 0, bsize, &fsize) != FR_OK) { fsize = LoadSupportFile(KEYDB_NAME, keydb, bsize); // load key database support file } - + u32 nkeys = 0; if (fsize && !(fsize % sizeof(AesKeyInfo))) nkeys = fsize / sizeof(AesKeyInfo); @@ -119,24 +119,24 @@ u32 LoadKeyFromFile(void* key, u32 keyslot, char type, char* id) { u8 keystore[16] __attribute__((aligned(32))) = {0}; bool found = false; - + // checking the obvious if ((keyslot >= 0x40) || ((type != 'X') && (type != 'Y') && (type != 'N') && (type != 'I'))) return 1; - + // check if already loaded if (!key && !id && (CheckKeySlot(keyslot, type) == 0)) return 0; - + // use keystore if key == NULL if (!key) key = keystore; - + // try to get key from 'aeskeydb.bin' file AesKeyInfo* keydb = (AesKeyInfo*) malloc(STD_BUFFER_SIZE); u32 nkeys = (keydb) ? LoadKeyDb(NULL, keydb, STD_BUFFER_SIZE) : 0; - + for (u32 i = 0; i < nkeys; i++) { AesKeyInfo* info = &(keydb[i]); - if (!((info->slot == keyslot) && (info->type == type) && + if (!((info->slot == keyslot) && (info->type == type) && ((!id && !(info->id[0])) || (id && (strncmp(id, info->id, 10) == 0))) && (!info->keyUnitType || (info->keyUnitType == GetUnitKeysType())))) continue; @@ -146,9 +146,9 @@ u32 LoadKeyFromFile(void* key, u32 keyslot, char type, char* id) memcpy(key, info->key, 16); break; } - + free(keydb); - + // load legacy slot0x??Key?.bin file instead if (!found && (type != 'I')) { char fname[64]; @@ -156,13 +156,13 @@ u32 LoadKeyFromFile(void* key, u32 keyslot, char type, char* id) (type == 'X') ? "X" : (type == 'Y') ? "Y" : (type == 'I') ? "IV" : "", (id) ? id : ""); found = (LoadSupportFile(fname, key, 16) == 16); } - + // key still not found (duh) if (!found) return 1; // out of options here - + // done if this is an IV if (type == 'I') return 0; - + // now, setup the key if (type == 'X') { setup_aeskeyX(keyslot, key); @@ -177,7 +177,7 @@ u32 LoadKeyFromFile(void* key, u32 keyslot, char type, char* id) keyYState |= 1ull << keyslot; } use_aeskey(keyslot); - + return 0; } @@ -186,11 +186,11 @@ u32 InitKeyDb(const char* path) // use this to quickly initialize all applicable keys in aeskeydb.bin static const u64 keyslot_whitelist = (1ull<<0x02)|(1ull<<0x03)|(1ull<<0x05)|(1ull<<0x18)|(1ull<<0x19)|(1ull<<0x1A)|(1ull<<0x1B)| (1ull<<0x1C)|(1ull<<0x1D)|(1ull<<0x1E)|(1ull<<0x1F)|(1ull<<0x24)|(1ull<<0x25)|(1ull<<0x2F); - + // try to load aeskeydb.bin file AesKeyInfo* keydb = (AesKeyInfo*) malloc(STD_BUFFER_SIZE); u32 nkeys = (keydb) ? LoadKeyDb(path, keydb, STD_BUFFER_SIZE) : 0; - + // apply all applicable keys for (u32 i = 0; i < nkeys; i++) { AesKeyInfo* info = &(keydb[i]); @@ -202,7 +202,7 @@ u32 InitKeyDb(const char* path) if ((info->type == 'I') || (*(info->id)) || (info->keyUnitType && (info->keyUnitType != GetUnitKeysType())) || (CheckKeySlot(info->slot, info->type) == 0)) continue; // most likely valid, but not applicable or already set if (info->isEncrypted) CryptAesKeyInfo(info); // decrypt key - + // apply key u8 key[16] __attribute__((aligned(32))) = {0}; char type = info->type; @@ -222,7 +222,7 @@ u32 InitKeyDb(const char* path) } use_aeskey(keyslot); } - + free(keydb); return (nkeys) ? 0 : 1; } @@ -236,15 +236,15 @@ u32 CheckRecommendedKeyDb(const char* path) 0x40, 0x76, 0x54, 0x3D, 0xA3, 0xFF, 0x91, 0x1C, 0xE1, 0xCC, 0x4E, 0xC7, 0x2F, 0x92, 0xE4, 0xB7, 0x2B, 0x24, 0x00, 0x15, 0xBE, 0x9B, 0xFC, 0xDE, 0x7F, 0xED, 0x95, 0x1D, 0xD5, 0xAB, 0x2D, 0xCB }; - + // try to load aeskeydb.bin file AesKeyInfo* keydb = (AesKeyInfo*) malloc(STD_BUFFER_SIZE); if (!keydb) return 1; u32 nkeys = LoadKeyDb(path, keydb, STD_BUFFER_SIZE); - + // compare with recommended SHA bool res = (nkeys && (sha_cmp(recommended_sha, keydb, nkeys * sizeof(AesKeyInfo), SHA256_MODE) == 0)); - + free(keydb); return res ? 0 : 1; } diff --git a/arm9/source/crypto/keydb.h b/arm9/source/crypto/keydb.h index e66cd63..48e56d2 100644 --- a/arm9/source/crypto/keydb.h +++ b/arm9/source/crypto/keydb.h @@ -14,10 +14,10 @@ #define KEYS_UNKNOWN 0 #define KEYS_DEVKIT 1 #define KEYS_RETAIL 2 - + typedef struct { - u8 slot; // keyslot, 0x00...0x3F + u8 slot; // keyslot, 0x00...0x3F char type; // type 'X' / 'Y' / 'N' for normalKey / 'I' for IV char id[10]; // key ID for special keys, all zero for standard keys u8 reserved[2]; // reserved space diff --git a/arm9/source/crypto/sha.c b/arm9/source/crypto/sha.c index 3be7ae9..b10004c 100644 --- a/arm9/source/crypto/sha.c +++ b/arm9/source/crypto/sha.c @@ -13,9 +13,9 @@ void sha_init(u32 mode) } void sha_update(const void* src, u32 size) -{ +{ const u32* src32 = (const u32*)src; - + while(size >= 0x40) { while(*REG_SHACNT & 1); *((volatile _sha_block*)REG_SHAINFIFO) = *((const _sha_block*)src32); diff --git a/arm9/source/fatfs/diskio.c b/arm9/source/fatfs/diskio.c index 8b2a753..2b3edd4 100644 --- a/arm9/source/fatfs/diskio.c +++ b/arm9/source/fatfs/diskio.c @@ -63,7 +63,7 @@ FATpartition DriveInfo[13] = { { TYPE_RAMDRV, SUBTYPE_NONE, 0, 0, 0xFF } // Z - RAMDRIVE }; -static BYTE imgnand_mode = 0x00; +static BYTE imgnand_mode = 0x00; @@ -81,7 +81,7 @@ DWORD get_fattime( void ) { ((DSTIMEGET(&dstime, bcd_D)&0x1F) << 16) | ((DSTIMEGET(&dstime, bcd_M)&0x0F) << 21) | (((DSTIMEGET(&dstime, bcd_Y)+(2000-1980))&0x7F) << 25); - + return fattime; } @@ -113,10 +113,10 @@ DSTATUS disk_initialize ( imgnand_mode = (GetMountState() & IMG_NAND) ? 0x01 : 0x00; FATpartition* fat_info = PART_INFO(pdrv); BYTE type = PART_TYPE(pdrv); - + fat_info->offset = fat_info->size = 0; fat_info->keyslot = 0xFF; - + if (type == TYPE_SDCARD) { if (sdmmc_sdcard_init() != 0) return STA_NOINIT|STA_NODISK; fat_info->size = getMMCDevice(1)->total_size; @@ -149,7 +149,7 @@ DSTATUS disk_initialize ( InitRamDrive(); fat_info->size = (GetRamDriveSize() + 0x1FF) / 0x200; } - + return RES_OK; } @@ -166,9 +166,9 @@ DRESULT disk_read ( DWORD sector, /* Sector address in LBA */ UINT count /* Number of sectors to read */ ) -{ +{ BYTE type = PART_TYPE(pdrv); - + if (type == TYPE_NONE) { return RES_PARERR; } else if (type == TYPE_SDCARD) { @@ -205,7 +205,7 @@ DRESULT disk_write ( ) { BYTE type = PART_TYPE(pdrv); - + if (type == TYPE_NONE) { return RES_PARERR; } else if (type == TYPE_SDCARD) { @@ -245,7 +245,7 @@ DRESULT disk_ioctl ( { BYTE type = PART_TYPE(pdrv); FATpartition* fat_info = PART_INFO(pdrv); - + switch (cmd) { case GET_SECTOR_SIZE: *((DWORD*) buff) = 0x200; @@ -262,7 +262,7 @@ DRESULT disk_ioctl ( // nothing else to do here - sdmmc.c handles the rest return RES_OK; } - + return RES_PARERR; } #endif diff --git a/arm9/source/filesys/fatmbr.c b/arm9/source/filesys/fatmbr.c index a3bfacb..530b9b9 100644 --- a/arm9/source/filesys/fatmbr.c +++ b/arm9/source/filesys/fatmbr.c @@ -5,7 +5,7 @@ u32 ValidateMbrHeader(MbrHeader* mbr) { u32 sector = 1; // check partitions for (u32 i = 0; i < 4; i++) { MbrPartitionInfo* partition = mbr->partitions + i; - if (!partition->count && i) continue; + if (!partition->count && i) continue; else if (!partition->count) return 1; // first partition can't be empty if ((partition->type != 0x1) && (partition->type != 0x4) && (partition->type != 0x6) && (partition->type != 0xB) && (partition->type != 0xC) && (partition->type != 0xE)) @@ -22,7 +22,7 @@ u32 ValidateFatHeader(void* fat) { if (strncmp(fat32->fs_type, "FAT32 ", 8) == 0) return 0; // is FAT32 header Fat16Header* fat16 = (Fat16Header*) fat; - if ((strncmp(fat16->fs_type, "FAT16 ", 8) == 0) || + if ((strncmp(fat16->fs_type, "FAT16 ", 8) == 0) || (strncmp(fat16->fs_type, "FAT12 ", 8) == 0) || (strncmp(fat16->fs_type, "FAT ", 8) == 0)) return 0; // is FAT16 / FAT12 header diff --git a/arm9/source/filesys/fatmbr.h b/arm9/source/filesys/fatmbr.h index a4e0583..4468942 100644 --- a/arm9/source/filesys/fatmbr.h +++ b/arm9/source/filesys/fatmbr.h @@ -15,7 +15,7 @@ typedef struct { typedef struct { char text[446]; - MbrPartitionInfo partitions[4]; + MbrPartitionInfo partitions[4]; u16 magic; // 0xAA55 } PACKED_ALIGN(2) MbrHeader; @@ -50,7 +50,7 @@ typedef struct { u32 clr_root; // 0x02 u16 sct_fsinfo; // 0x01 u16 sct_backup; // 0x06 - u8 reserved3[12]; + u8 reserved3[12]; u8 ndrive; // 0x80 u8 head_cur; // 0x00 u8 boot_sig; // 0x29 diff --git a/arm9/source/filesys/filetype.c b/arm9/source/filesys/filetype.c index 4d7e51b..8c15fe2 100644 --- a/arm9/source/filesys/filetype.c +++ b/arm9/source/filesys/filetype.c @@ -112,7 +112,7 @@ u64 IdentifyFileType(const char* path) { } } } - + if (fsize == sizeof(TitleInfoEntry) && (strncasecmp(path, "T:/", 3) == 0)) { const char* mntpath = GetMountPath(); if (mntpath && *mntpath) { @@ -183,6 +183,6 @@ u64 IdentifyFileType(const char* path) { if (FileGetSize(path_cdn) > 0) return GAME_NUSCDN; // NUS/CDN type 1 } - + return 0; } diff --git a/arm9/source/filesys/fsdrive.c b/arm9/source/filesys/fsdrive.c index 72297b6..1122387 100644 --- a/arm9/source/filesys/fsdrive.c +++ b/arm9/source/filesys/fsdrive.c @@ -16,7 +16,7 @@ static bool search_title_mode = false; int DriveType(const char* path) { int type = DRV_UNKNOWN; int pdrv = GetMountedFSNum(path); - + if (CheckAliasDrive(path)) { type = DRV_FAT | DRV_ALIAS | ((*path == 'A') ? DRV_SYSNAND : DRV_EMUNAND); } else if (*search_pattern && *search_path && (strncmp(path, "Z:", 3) == 0)) { @@ -39,7 +39,7 @@ int DriveType(const char* path) { } else if ((pdrv >= 7) && (pdrv <= 9) && (GetMountState() & (IMG_FAT|IMG_NAND))) { type = DRV_FAT | DRV_IMAGE | DRV_STDFAT; - } + } } else if (CheckVirtualDrive(path)) { int vsrc = GetVirtualSource(path); if (vsrc == VRT_SYSNAND) { @@ -58,9 +58,9 @@ int DriveType(const char* path) { type = DRV_VIRTUAL | DRV_CART; } else if (vsrc == VRT_VRAM) { type = DRV_VIRTUAL | DRV_VRAM; - } + } } - + return type; } @@ -82,14 +82,14 @@ bool GetRootDirContentsWorker(DirStruct* contents) { static const char* drvname[] = { FS_DRVNAME }; static const char* drvnum[] = { FS_DRVNUM }; u32 n_entries = 0; - + char sdlabel[DRV_LABEL_LEN]; if (!GetFATVolumeLabel("0:", sdlabel) || !(*sdlabel)) strcpy(sdlabel, "NOLABEL"); char carttype[16]; GetVCartTypeString(carttype); - + // virtual root objects hacked in for (u32 i = 0; (i < countof(drvnum)) && (n_entries < MAX_DIR_ENTRIES); i++) { DirEntry* entry = &(contents->entry[n_entries]); @@ -124,7 +124,7 @@ bool GetRootDirContentsWorker(DirStruct* contents) { n_entries++; } contents->n_entries = n_entries; - + return contents->n_entries; } @@ -133,11 +133,11 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const ch FILINFO fno; char* fname = fpath + strnlen(fpath, fnsize - 1); bool ret = false; - + if (fvx_opendir(&pdir, fpath) != FR_OK) return false; if (*(fname-1) != '/') *(fname++) = '/'; - + while (fvx_readdir(&pdir, &fno) == FR_OK) { if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0)) continue; // filter out virtual entries @@ -176,7 +176,7 @@ bool GetDirContentsWorker(DirStruct* contents, char* fpath, int fnsize, const ch } } fvx_closedir(&pdir); - + return ret; } @@ -222,7 +222,7 @@ uint64_t GetFreeSpace(const char* path) int pdrv = GetMountedFSNum(path); FATFS* fsobj = GetMountedFSObject(path); if ((pdrv < 0) || !fsobj) return 0; - + snprintf(fsname, 3, "%i:", pdrv); if (f_getfree(fsname, &free_clusters, &fsptr) != FR_OK) return 0; diff --git a/arm9/source/filesys/fsdrive.h b/arm9/source/filesys/fsdrive.h index d0922d6..3b94259 100644 --- a/arm9/source/filesys/fsdrive.h +++ b/arm9/source/filesys/fsdrive.h @@ -40,7 +40,7 @@ "MEMORY VIRTUAL", \ "VRAM VIRTUAL", \ "LAST SEARCH" \ - + #define FS_DRVNUM \ "0:", "1:", "2:", "3:", "A:", "S:", "4:", "5:", "6:", "B:", "E:", "7:", "8:", "9:", "I:", "C:", "G:", "K:", "T:", "D:", "M:", "V:", "Z:" diff --git a/arm9/source/filesys/fsgame.c b/arm9/source/filesys/fsgame.c index 4d08899..0457bab 100644 --- a/arm9/source/filesys/fsgame.c +++ b/arm9/source/filesys/fsgame.c @@ -25,7 +25,7 @@ bool GoodRenamer(DirEntry* entry, bool ask) { if ((GetGoodName(goodname, entry->path, false) != 0) || (strncmp(goodname + strnlen(goodname, 256) - 4, ".tmd", 4) == 0)) // no TMD, please return false; - + if (ask) { // ask for confirmatiom char oldname_tr[32+1]; char newname_ww[256]; @@ -35,7 +35,7 @@ bool GoodRenamer(DirEntry* entry, bool ask) { if (!ShowPrompt(true, "%s\nRename to good name?\n \n%s", oldname_tr, newname_ww)) return true; // call it a success because user choice } - + char npath[256]; // get new path strncpy(npath, entry->path, 256); char* nname = strrchr(npath, '/'); @@ -47,6 +47,6 @@ bool GoodRenamer(DirEntry* entry, bool ask) { if (f_rename(entry->path, npath) != FR_OK) return false; strncpy(entry->path, npath, 256); entry->name = entry->path + (nname - npath); - + return true; } diff --git a/arm9/source/filesys/fsinit.c b/arm9/source/filesys/fsinit.c index f9f553b..c80d34e 100644 --- a/arm9/source/filesys/fsinit.c +++ b/arm9/source/filesys/fsinit.c @@ -18,7 +18,7 @@ bool InitSDCardFS() { bool InitExtFS() { static bool ramdrv_ready = false; - + for (u32 i = 1; i < NORM_FS; i++) { char fsname[8]; snprintf(fsname, 7, "%lu:", i); diff --git a/arm9/source/filesys/fsinit.h b/arm9/source/filesys/fsinit.h index 6ada3e6..c3ab7ec 100644 --- a/arm9/source/filesys/fsinit.h +++ b/arm9/source/filesys/fsinit.h @@ -6,7 +6,7 @@ // init SD card filesystem - required(?) for everything else bool InitSDCardFS(); -// init fill external fileystem +// init fill external fileystem bool InitExtFS(); // mount and init image file system @@ -21,7 +21,7 @@ void DeinitSDCardFS(); // dismount drives of a certain type void DismountDriveType(u32 type); -// returns the mount state of the SD card +// returns the mount state of the SD card bool CheckSDMountState(void); // get number of mounted file system (only for FATFS filesystems) diff --git a/arm9/source/filesys/fsperm.c b/arm9/source/filesys/fsperm.c index 2a68bea..f32914c 100644 --- a/arm9/source/filesys/fsperm.c +++ b/arm9/source/filesys/fsperm.c @@ -7,7 +7,7 @@ #include "ui.h" #include "sdmmc.h" -#define PATH_SYS_LVL1 "S:/twln.bin", "S:/twlp.bin" +#define PATH_SYS_LVL1 "S:/twln.bin", "S:/twlp.bin" #define PATH_SYS_LVL2 "1:/rw/sys/LocalFriendCodeSeed_B", "1:/rw/sys/LocalFriendCodeSeed_A", \ "1:/rw/sys/SecureInfo_A", "1:/rw/sys/SecureInfo_B", \ "1:/private/movable.sed", "1:/ro/sys/HWCAL0.dat", "1:/ro/sys/HWCAL1.dat", \ @@ -23,7 +23,7 @@ bool CheckWritePermissions(const char* path) { char area_name[16]; int drvtype = DriveType(path); u32 perm; - + // create a standardized path string char path_f[256]; char* p = (char*) path; @@ -37,13 +37,13 @@ bool CheckWritePermissions(const char* path) { // check mounted image write permissions if ((drvtype & DRV_IMAGE) && !CheckWritePermissions(GetMountPath())) return false; // endless loop when mounted file inside image, but not possible - + // SD card write protection check if ((drvtype & (DRV_SDCARD | DRV_EMUNAND | DRV_ALIAS)) && SD_WRITE_PROTECTED) { ShowPrompt(false, "SD card is write protected!\nCan't continue."); return false; } - + // check drive type, get permission type if (drvtype & DRV_SYSNAND) { static const u32 perms[] = { PERM_SYS_LVL0, PERM_SYS_LVL1, PERM_SYS_LVL2, PERM_SYS_LVL3 }; @@ -104,20 +104,20 @@ bool CheckWritePermissions(const char* path) { } else { return false; } - + // check permission, return if already set if ((write_permissions & perm) == perm) return true; - + // offer unlock if possible if (!(perm & (PERM_VRAM|PERM_GAME|PERM_XORPAD))) { // ask the user if (!ShowPrompt(true, "Writing to %s is locked!\nUnlock it now?", area_name)) return false; - + return SetWritePermissions(perm, true); } - + // unlock not possible ShowPrompt(false, "Unlock write permission for\n%s is not allowed.", area_name); return false; @@ -141,7 +141,7 @@ bool SetWritePermissions(u32 perm, bool add_perm) { if (!add_perm) write_permissions = perm; return true; } - + switch (perm) { case PERM_BASE: if (!ShowUnlockSequence(1, "You want to enable base\nwriting permissions.")) @@ -207,9 +207,9 @@ bool SetWritePermissions(u32 perm, bool add_perm) { break; #endif } - + write_permissions = add_perm ? write_permissions | perm : perm; - + return true; } diff --git a/arm9/source/filesys/fsutil.c b/arm9/source/filesys/fsutil.c index 0219985..ecf2390 100644 --- a/arm9/source/filesys/fsutil.c +++ b/arm9/source/filesys/fsutil.c @@ -43,19 +43,19 @@ bool FormatSDCard(u64 hidden_mb, u32 cluster_size, const char* label) { u32 emu_size = (u32) ((hidden_mb * 1024 * 1024) / 512); u32 fat_sector = align(emu_sector + emu_size, 0x2000); // align to 4MB u32 fat_size = (fat_sector < sd_size) ? sd_size - fat_sector : 0; - + // FAT size check if (fat_size < 0x80000) { // minimum free space: 256MB ShowPrompt(false, "Error: SD card is too small"); return false; } - + // Write protection check if (SD_WRITE_PROTECTED) { ShowPrompt(false, "SD card is write protected!\nCan't continue."); return false; } - + // build the MBR memcpy(mbrdata + 0x08, &fat_sector, 4); memcpy(mbrdata + 0x0C, &fat_size, 4); @@ -64,13 +64,13 @@ bool FormatSDCard(u64 hidden_mb, u32 cluster_size, const char* label) { memcpy(mbr + 0x1BE, mbrdata, 0x42); if (hidden_mb) memcpy(mbr, "GATEWAYNAND", 12); // legacy else memset(mbr + 0x1CE, 0, 0x10); - + // one last warning.... // 0:/Nintendo 3DS/ write permission is ignored here, this warning is enough if (!ShowUnlockSequence(5, "!WARNING!\n \nProceeding will format this SD.\nThis will irreversibly delete\nALL data on it.")) return false; - ShowString("Formatting SD, please wait..."); - + ShowString("Formatting SD, please wait..."); + // write the MBR to disk // !this assumes a fully deinitialized file system! if ((sdmmc_sdcard_init() != 0) || (sdmmc_sdcard_writesectors(0, 1, mbr) != 0) || @@ -78,11 +78,11 @@ bool FormatSDCard(u64 hidden_mb, u32 cluster_size, const char* label) { ShowPrompt(false, "Error: SD card i/o failure"); return false; } - + // format the SD card VolToPart[0].pt = 1; // workaround to prevent FatFS rebuilding the MBR InitSDCardFS(); - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) bkpt; // will not happen MKFS_PARM opt0, opt1; @@ -92,14 +92,14 @@ bool FormatSDCard(u64 hidden_mb, u32 cluster_size, const char* label) { opt0.align = opt1.align = 0; opt0.n_fat = opt1.n_fat = 1; opt0.n_root = opt1.n_root = 0; - bool ret = ((f_mkfs("0:", &opt0, buffer, STD_BUFFER_SIZE) == FR_OK) || + bool ret = ((f_mkfs("0:", &opt0, buffer, STD_BUFFER_SIZE) == FR_OK) || (f_mkfs("0:", &opt1, buffer, STD_BUFFER_SIZE) == FR_OK)) && (f_setlabel((label) ? label : "0:GM9SD") == FR_OK); free(buffer); - + DeinitSDCardFS(); VolToPart[0].pt = 0; // revert workaround to prevent SD mount problems - + return ret; } @@ -108,12 +108,12 @@ bool SetupBonusDrive(void) { return false; ShowString("Formatting drive, please wait..."); if (GetMountState() & IMG_NAND) InitImgFS(NULL); - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) bkpt; bool ret = (f_mkfs("8:", NULL, buffer, STD_BUFFER_SIZE) == FR_OK); free(buffer); - + if (ret) { f_setlabel("8:BONUS"); InitExtFS(); @@ -124,12 +124,12 @@ bool SetupBonusDrive(void) { bool FileUnlock(const char* path) { FIL file; FRESULT res; - + if (!(DriveType(path) & DRV_FAT)) return true; // can't really check this if ((res = fx_open(&file, path, FA_READ | FA_OPEN_EXISTING)) != FR_OK) { char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - if (GetMountState() && (res == FR_LOCKED) && + if (GetMountState() && (res == FR_LOCKED) && (ShowPrompt(true, "%s\nFile is currently mounted.\nUnmount to unlock?", pathstr))) { InitImgFS(NULL); if (fx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) @@ -137,7 +137,7 @@ bool FileUnlock(const char* path) { } else return false; } fx_close(&file); - + return true; } @@ -165,19 +165,19 @@ bool FileGetSha256(const char* path, u8* sha256, u64 offset, u64 size) { bool ret = true; FIL file; u64 fsize; - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return false; - + fsize = fvx_size(&file); if (offset + size > fsize) return false; if (!size) size = fsize - offset; fvx_lseek(&file, offset); - + u32 bufsiz = min(STD_BUFFER_SIZE, fsize); u8* buffer = (u8*) malloc(bufsiz); if (!buffer) return false; - + ShowProgress(0, 0, path); sha_init(SHA256_MODE); for (u64 pos = 0; (pos < size) && ret; pos += bufsiz) { @@ -189,13 +189,13 @@ bool FileGetSha256(const char* path, u8* sha256, u64 offset, u64 size) { ret = false; sha_update(buffer, bytes_read); } - + sha_get(sha256); fvx_close(&file); free(buffer); - + ShowProgress(1, 1, path); - + return ret; } @@ -203,13 +203,13 @@ u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file) { FIL file; // used for FAT & virtual u64 found = (u64) -1; u64 fsize = FileGetSize(path); - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return found; - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) return false; - + // main routine for (u32 pass = 0; pass < 2; pass++) { bool show_progress = false; @@ -236,10 +236,10 @@ u32 FileFindData(const char* path, u8* data, u32 size_data, u32 offset_file) { break; } } - + free(buffer); fvx_close(&file); - + return found; } @@ -247,13 +247,13 @@ bool FileInjectFile(const char* dest, const char* orig, u64 off_dest, u64 off_or FIL ofile; FIL dfile; bool allow_expand = (flags && (*flags & ALLOW_EXPAND)); - + if (!CheckWritePermissions(dest)) return false; if (strncasecmp(dest, orig, 256) == 0) { ShowPrompt(false, "Error: Can't inject file into itself"); return false; } - + // open destination / origin if (fvx_open(&dfile, dest, FA_WRITE | ((allow_expand) ? FA_OPEN_ALWAYS : FA_OPEN_EXISTING)) != FR_OK) return false; @@ -266,7 +266,7 @@ bool FileInjectFile(const char* dest, const char* orig, u64 off_dest, u64 off_or fvx_lseek(&ofile, off_orig); if (!size && (off_orig < fvx_size(&ofile))) size = fvx_size(&ofile) - off_orig; - + // check file limits if (!allow_expand && (off_dest + size > fvx_size(&dfile))) { ShowPrompt(false, "Operation would write beyond end of file"); @@ -279,10 +279,10 @@ bool FileInjectFile(const char* dest, const char* orig, u64 off_dest, u64 off_or fvx_close(&ofile); return false; } - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) return false; - + bool ret = true; ShowProgress(0, 0, orig); for (u64 pos = 0; (pos < size) && ret; pos += STD_BUFFER_SIZE) { @@ -302,39 +302,39 @@ bool FileInjectFile(const char* dest, const char* orig, u64 off_dest, u64 off_or } } ShowProgress(1, 1, orig); - + free(buffer); fvx_close(&dfile); fvx_close(&ofile); - + return ret; } bool FileSetByte(const char* dest, u64 offset, u64 size, u8 fillbyte, u32* flags) { FIL dfile; bool allow_expand = (flags && (*flags & ALLOW_EXPAND)); - + if (!CheckWritePermissions(dest)) return false; - + // open destination if (fvx_open(&dfile, dest, FA_WRITE | ((allow_expand) ? FA_OPEN_ALWAYS : FA_OPEN_EXISTING)) != FR_OK) return false; fvx_lseek(&dfile, offset); if (!size && (offset < fvx_size(&dfile))) size = fvx_size(&dfile) - offset; - + // check file limits if (!allow_expand && (offset + size > fvx_size(&dfile))) { ShowPrompt(false, "Operation would write beyond end of file"); fvx_close(&dfile); return false; } - + u32 bufsiz = min(STD_BUFFER_SIZE, size); u8* buffer = (u8*) malloc(bufsiz); if (!buffer) return false; memset(buffer, fillbyte, bufsiz); - + bool ret = true; ShowProgress(0, 0, dest); for (u64 pos = 0; (pos < size) && ret; pos += bufsiz) { @@ -352,10 +352,10 @@ bool FileSetByte(const char* dest, u64 offset, u64 size, u8 fillbyte, u32* flags } } ShowProgress(1, 1, dest); - + free(buffer); fvx_close(&dfile); - + return ret; } @@ -364,7 +364,7 @@ bool FileCreateDummy(const char* cpath, const char* filename, u64 size) { if (!CheckWritePermissions(cpath)) return false; if (filename) snprintf(npath, 255, "%s/%s", cpath, filename); else snprintf(npath, 255, "%s", cpath); - + // create dummy file (fail if already existing) // then, expand the file size via cluster preallocation FIL dfile; @@ -373,7 +373,7 @@ bool FileCreateDummy(const char* cpath, const char* filename, u64 size) { f_lseek(&dfile, size > 0xFFFFFFFF ? 0xFFFFFFFF : (FSIZE_t) size); f_sync(&dfile); fx_close(&dfile); - + return (fa_stat(npath, NULL) == FR_OK); } @@ -425,7 +425,7 @@ bool DirInfoWorker(char* fpath, bool virtual, u64* tsize, u32* tdirs, u32* tfile } f_closedir(&pdir); } - + return ret; } @@ -449,20 +449,20 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, bool append = (flags && (*flags & APPEND_ALL)); bool calcsha = (flags && (*flags & CALC_SHA) && !append); bool ret = false; - + // check destination write permission (special paths only) if (((*dest == '1') || (strncmp(dest, "0:/Nintendo 3DS", 16) == 0)) && - (!flags || !(*flags & OVERRIDE_PERM)) && + (!flags || !(*flags & OVERRIDE_PERM)) && !CheckWritePermissions(dest)) return false; - + FILINFO fno; if (fvx_stat(orig, &fno) != FR_OK) return false; // origin does not exist if (move && (to_virtual || fno.fattrib & AM_VRT)) return false; // trying to move a virtual file - + // path string (for output) char deststr[36 + 1]; TruncateString(deststr, dest, 36, 8); - + // the copy process takes place here if (!ShowProgress(0, 0, orig) && !(flags && (*flags & NO_CANCEL))) { if (ShowPrompt(true, "%s\nB button detected. Cancel?", deststr)) return false; @@ -473,12 +473,12 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, } else if (fno.fattrib & AM_DIR) { // processing folders (same for move & copy) DIR pdir; char* fname = orig + strnlen(orig, 256); - + if (append) { if (!silent) ShowPrompt(false, "%s\nError: Cannot append a folder", deststr); return false; } - + // create the destination folder if it does not already exist if (fvx_opendir(&pdir, dest) != FR_OK) { if (fvx_mkdir(dest) != FR_OK) { @@ -486,11 +486,11 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, return false; } } else fvx_closedir(&pdir); - + if (fvx_opendir(&pdir, orig) != FR_OK) return false; *(fname++) = '/'; - + while (fvx_readdir(&pdir, &fno) == FR_OK) { if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0)) continue; // filter out virtual entries @@ -509,7 +509,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, if (!res) break; } } - + fvx_closedir(&pdir); *(--fname) = '\0'; } else if (move) { // moving if destination exists @@ -525,20 +525,20 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, FIL dfile; u64 osize; u64 dsize; - + if (fvx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK) { if (!FileUnlock(orig) || (fvx_open(&ofile, orig, FA_READ | FA_OPEN_EXISTING) != FR_OK)) return false; ShowProgress(0, 0, orig); // reinit progress bar } - + if ((!append || (fvx_open(&dfile, dest, FA_WRITE | FA_OPEN_EXISTING) != FR_OK)) && (fvx_open(&dfile, dest, FA_WRITE | FA_CREATE_ALWAYS) != FR_OK)) { if (!silent) ShowPrompt(false, "%s\nError: Cannot open destination file", deststr); fvx_close(&ofile); return false; } - + ret = true; // destination file exists by now, so we need to handle deletion osize = fvx_size(&ofile); dsize = append ? fvx_size(&dfile) : 0; // always 0 if not appending to file @@ -546,16 +546,16 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, if (!silent) ShowPrompt(false, "%s\nError: Not enough space available", deststr); ret = false; } - + fvx_lseek(&dfile, dsize); fvx_sync(&dfile); fvx_lseek(&ofile, 0); fvx_sync(&ofile); - + if (calcsha) sha_init(SHA256_MODE); for (u64 pos = 0; (pos < osize) && ret; pos += bufsiz) { UINT bytes_read = 0; - UINT bytes_written = 0; + UINT bytes_written = 0; if ((fvx_read(&ofile, buffer, bufsiz, &bytes_read) != FR_OK) || (fvx_write(&dfile, buffer, bytes_read, &bytes_written) != FR_OK) || (bytes_read != bytes_written)) @@ -574,7 +574,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, sha_update(buffer, bytes_read); } ShowProgress(1, 1, orig); - + fvx_close(&ofile); fvx_close(&dfile); if (!ret && ((dsize == 0) || (fvx_lseek(&dfile, dsize) != FR_OK) || (f_truncate(&dfile) != FR_OK))) { @@ -587,7 +587,7 @@ bool PathMoveCopyRec(char* dest, char* orig, u32* flags, bool move, u8* buffer, FileSetData(dest, sha256, 0x20, 0, true); } } - + return ret; } @@ -597,10 +597,10 @@ bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move) { if (!CheckWritePermissions(dest)) return false; if (move && !CheckDirWritePermissions(orig)) return false; } - + // reset local flags if (flags) *flags = *flags & ~(SKIP_CUR|OVERWRITE_CUR); - + // preparations int ddrvtype = DriveType(dest); int odrvtype = DriveType(orig); @@ -610,32 +610,32 @@ bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move) { strncpy(lorig, orig, 255); char deststr[36 + 1]; TruncateString(deststr, ldest, 36, 8); - + // moving only for regular FAT drives (= not alias drives) if (move && !(ddrvtype & odrvtype & DRV_STDFAT)) { ShowPrompt(false, "Error: Only FAT files can be moved"); return false; } - + // is destination part of origin? u32 olen = strnlen(lorig, 255); if ((strncasecmp(ldest, lorig, olen) == 0) && (ldest[olen] == '/')) { ShowPrompt(false, "%s\nError: Destination is part of origin", deststr); return false; } - + if (!(ddrvtype & DRV_VIRTUAL)) { // FAT destination handling // get destination name char* dname = strrchr(ldest, '/'); if (!dname) return false; dname++; - + // check & fix destination == origin while (strncasecmp(ldest, lorig, 255) == 0) { if (!ShowKeyboardOrPrompt(dname, 255 - (dname - ldest), "%s\nDestination equals origin\nChoose another name?", deststr)) return false; } - + // check if destination exists if (flags && !(*flags & (OVERWRITE_CUR|OVERWRITE_ALL|APPEND_ALL)) && (fa_stat(ldest, NULL) == FR_OK)) { if (*flags & SKIP_ALL) { @@ -665,29 +665,29 @@ bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move) { return false; } } - + // ensure the destination path exists if (flags && (*flags & BUILD_PATH)) fvx_rmkpath(ldest); - + // setup buffer u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { ShowPrompt(false, "Out of memory."); return false; } - + // actual move / copy operation bool same_drv = (strncasecmp(lorig, ldest, 2) == 0); bool res = PathMoveCopyRec(ldest, lorig, flags, move && same_drv, buffer, STD_BUFFER_SIZE); if (move && res && (!flags || !(*flags&SKIP_CUR))) PathDelete(lorig); - + free(buffer); return res; } else { // virtual destination handling // can't write an SHA file to a virtual destination if (flags) *flags &= ~CALC_SHA; bool force_unmount = false; - + // handle NAND image unmounts if ((ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)) && !(GetVirtualSource(dest) & (VRT_DISADIFF | VRT_BDRI))) { FILINFO fno; @@ -695,31 +695,31 @@ bool PathMoveCopy(const char* dest, const char* orig, u32* flags, bool move) { if ((fvx_stat(ldest, &fno) == FR_OK) && (fno.fsize > 4 * 1024 * 1024)) force_unmount = true; } - + // prevent illegal operations if (force_unmount && (odrvtype & ddrvtype & (DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE))) { ShowPrompt(false, "Copy operation is not allowed"); - return false; + return false; } - + // check destination == origin if (strncasecmp(ldest, lorig, 255) == 0) { ShowPrompt(false, "%s\nDestination equals origin", deststr); return false; } - + // setup buffer u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { ShowPrompt(false, "Out of memory."); return false; } - + // actual virtual copy operation if (force_unmount) DismountDriveType(DriveType(ldest)&(DRV_SYSNAND|DRV_EMUNAND|DRV_IMAGE)); bool res = PathMoveCopyRec(ldest, lorig, flags, false, buffer, STD_BUFFER_SIZE); if (force_unmount) InitExtFS(); - + free(buffer); return res; } @@ -731,7 +731,7 @@ bool PathCopy(const char* destdir, const char* orig, u32* flags) { char* oname = strrchr(orig, '/'); if (oname == NULL) return false; // not a proper origin path snprintf(dest, 255, "%s/%s", destdir, (++oname)); - + // virtual destination special handling if (GetVirtualSource(destdir) & ~VRT_BDRI) { u64 osize = FileGetSize(orig); @@ -762,7 +762,7 @@ bool PathCopy(const char* destdir, const char* orig, u32* flags) { } } } - + return PathMoveCopy(dest, orig, flags, false); } @@ -772,7 +772,7 @@ bool PathMove(const char* destdir, const char* orig, u32* flags) { char* oname = strrchr(orig, '/'); if (oname == NULL) return false; // not a proper origin path snprintf(dest, 255, "%s/%s", destdir, (++oname)); - + return PathMoveCopy(dest, orig, flags, true); } @@ -784,13 +784,13 @@ bool PathDelete(const char* path) { bool PathRename(const char* path, const char* newname) { char npath[256]; // 256 is the maximum length of a full path char* oldname = strrchr(path, '/'); - + if (!CheckDirWritePermissions(path)) return false; if (!oldname) return false; oldname++; strncpy(npath, path, oldname - path); strncpy(npath + (oldname - path), newname, 255 - (oldname - path)); - + if (fvx_rename(path, npath) != FR_OK) return false; if ((strncasecmp(path, npath, 256) != 0) && ((fvx_stat(path, NULL) == FR_OK) || (fvx_stat(npath, NULL) != FR_OK))) @@ -808,18 +808,18 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const char path_local[256]; strncpy(path_local, path, 256); path_local[255] = '\0'; - + bool no_dirs = flags & NO_DIRS; bool no_files = flags & NO_FILES; bool hide_ext = flags & HIDE_EXT; bool select_dirs = flags & SELECT_DIRS; - + // main loop while (true) { u32 n_found = 0; u32 pos = 0; GetDirContents(contents, path_local); - + while (pos < contents->n_entries) { char opt_names[_MAX_FS_OPT+1][32+1]; DirEntry* res_entry[MAX_DIR_ENTRIES+1] = { NULL }; @@ -834,7 +834,7 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const snprintf(opt_names[n_opt++], 32, "[more...]"); break; } - + if (!new_style) { char temp_str[256]; snprintf(temp_str, 256, "%s", entry->name); @@ -850,7 +850,7 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const if ((pos >= contents->n_entries) && (n_opt < n_found) && !new_style) snprintf(opt_names[n_opt++], 32, "[more...]"); if (!n_opt) break; - + const char* optionstr[_MAX_FS_OPT+1] = { NULL }; for (u32 i = 0; i <= _MAX_FS_OPT; i++) optionstr[i] = opt_names[i]; u32 user_select = new_style ? ShowFileScrollPrompt(n_opt, (const DirEntry**)res_entry, hide_ext, "%s", text) @@ -874,7 +874,7 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const char pathstr[32+1]; TruncateString(pathstr, path_local, 32, 8); ShowPrompt(false, "%s\nNo usable entries found.", pathstr); - return false; + return false; } } } @@ -882,7 +882,7 @@ bool FileSelectorWorker(char* result, const char* text, const char* path, const bool FileSelector(char* result, const char* text, const char* path, const char* pattern, u32 flags, bool new_style) { void* buffer = (void*) malloc(sizeof(DirStruct)); if (!buffer) return false; - + bool ret = FileSelectorWorker(result, text, path, pattern, flags, buffer, new_style); free(buffer); return ret; diff --git a/arm9/source/filesys/image.c b/arm9/source/filesys/image.c index a7237dc..5289d0c 100644 --- a/arm9/source/filesys/image.c +++ b/arm9/source/filesys/image.c @@ -17,7 +17,7 @@ int ReadImageBytes(void* buffer, u64 offset, u64 count) { if (!mount_state) return FR_INVALID_OBJECT; if (fvx_tell(&mount_file) != offset) { if (fvx_size(&mount_file) < offset) return -1; - fvx_lseek(&mount_file, offset); + fvx_lseek(&mount_file, offset); } ret = fvx_read(&mount_file, buffer, count, &bytes_read); return (ret != 0) ? (int) ret : (bytes_read != count) ? -1 : 0; diff --git a/arm9/source/filesys/sddata.c b/arm9/source/filesys/sddata.c index efaa6f6..65ff846 100644 --- a/arm9/source/filesys/sddata.c +++ b/arm9/source/filesys/sddata.c @@ -42,7 +42,7 @@ void dealias_path (TCHAR* alias, const TCHAR* path) { FilCryptInfo* fx_find_cryptinfo(FIL* fptr) { FilCryptInfo* info = NULL; - + for (u32 i = 0; i < NUM_FILCRYPTINFO; i++) { if (!info && !filcrypt[i].fptr) // use first free info = &filcrypt[i]; @@ -51,7 +51,7 @@ FilCryptInfo* fx_find_cryptinfo(FIL* fptr) { break; } } - + return info; } @@ -59,27 +59,27 @@ FRESULT fx_decrypt_dsiware (FIL* fp, void* buff, FSIZE_t ofs, UINT len) { const u32 mode = AES_CNT_TITLEKEY_DECRYPT_MODE; const u32 num_tbl = sizeof(TadContentTable) / sizeof(u32); const FSIZE_t ofs0 = f_tell(fp); - + u8 __attribute__((aligned(16))) iv[AES_BLOCK_SIZE]; u32 tbl[num_tbl]; u8 hdr[TAD_HEADER_LEN]; - + FRESULT res; UINT br; - - + + // read and decrypt header if ((res = f_lseek(fp, TAD_HEADER_OFFSET)) != FR_OK) return res; if ((res = f_read(fp, hdr, TAD_HEADER_LEN, &br)) != FR_OK) return res; if (br != TAD_HEADER_LEN) return FR_DENIED; memcpy(iv, hdr + TAD_HEADER_LEN - AES_BLOCK_SIZE, AES_BLOCK_SIZE); cbc_decrypt(hdr, hdr, sizeof(TadHeader) / AES_BLOCK_SIZE, mode, iv); - + // setup the table if (BuildTadContentTable(tbl, hdr) != 0) return FR_DENIED; if (tbl[num_tbl-1] > f_size(fp)) return FR_DENIED; // obviously missing data - - + + // process sections u32 sct_start = 0; u32 sct_end = 0; @@ -87,21 +87,21 @@ FRESULT fx_decrypt_dsiware (FIL* fp, void* buff, FSIZE_t ofs, UINT len) { sct_end = tbl[i]; if (sct_start == sct_end) continue; // nothing in section if ((ofs + len <= sct_start) || (ofs >= sct_end)) continue; // section not in data - + const u32 crypt_end = sct_end - (AES_BLOCK_SIZE * 2); const u32 data_end = min(crypt_end, ofs + len); u32 data_pos = max(ofs, sct_start); if (ofs >= crypt_end) continue; // nothing to do - + if ((sct_start < ofs) || (sct_end > ofs + len)) { // incomplete section, ugh u8 __attribute__((aligned(16))) block[AES_BLOCK_SIZE]; - + // load iv0 FSIZE_t block0_ofs = data_pos - (data_pos % AES_BLOCK_SIZE); FSIZE_t iv0_ofs = ((block0_ofs > sct_start) ? block0_ofs : sct_end) - AES_BLOCK_SIZE; if ((res = f_lseek(fp, iv0_ofs)) != FR_OK) return res; if ((res = f_read(fp, iv, AES_BLOCK_SIZE, &br)) != FR_OK) return res; - + // load and decrypt block0 (if misaligned) if (data_pos % AES_BLOCK_SIZE) { if ((res = f_lseek(fp, block0_ofs)) != FR_OK) return res; @@ -110,7 +110,7 @@ FRESULT fx_decrypt_dsiware (FIL* fp, void* buff, FSIZE_t ofs, UINT len) { data_pos = min(block0_ofs + AES_BLOCK_SIZE, data_end); memcpy(buff, block + (ofs - block0_ofs), data_pos - ofs); } - + // decrypt blocks in between u32 num_blocks = (data_end - data_pos) / AES_BLOCK_SIZE; if (num_blocks) { @@ -118,7 +118,7 @@ FRESULT fx_decrypt_dsiware (FIL* fp, void* buff, FSIZE_t ofs, UINT len) { cbc_decrypt(blocks, blocks, num_blocks, mode, iv); data_pos += num_blocks * AES_BLOCK_SIZE; } - + // decrypt last block if (data_pos < data_end) { u8* lbuff = (u8*) buff + (data_pos - ofs); @@ -137,7 +137,7 @@ FRESULT fx_decrypt_dsiware (FIL* fp, void* buff, FSIZE_t ofs, UINT len) { cbc_decrypt(blocks, blocks, num_blocks, mode, iv); } } - + return f_lseek(fp, ofs0); } @@ -145,7 +145,7 @@ FRESULT fx_open (FIL* fp, const TCHAR* path, BYTE mode) { int num = alias_num(path); FilCryptInfo* info = fx_find_cryptinfo(fp); if (info) info->fptr = NULL; - + if (info && (num >= 0)) { // DSIWare Export, mark with the magic number if (strncmp(path + 2, "/" DSIWARE_MAGIC, 1 + 16) == 0) { @@ -172,7 +172,7 @@ FRESULT fx_open (FIL* fp, const TCHAR* path, BYTE mode) { memcpy(info->keyy, sd_keyy[num], 16); info->fptr = fp; } - + return fa_open(fp, path, mode); } @@ -193,12 +193,12 @@ FRESULT fx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) { FilCryptInfo* info = fx_find_cryptinfo(fp); FSIZE_t off = f_tell(fp); FRESULT res = FR_OK; - + if (info && info->fptr) { if (memcmp(info->ctr, DSIWARE_MAGIC, 16) == 0) return FR_DENIED; void* crypt_buff = (void*) malloc(min(btw, STD_BUFFER_SIZE)); if (!crypt_buff) return FR_DENIED; - + setup_aeskeyY(0x34, info->keyy); use_aeskey(0x34); *bw = 0; @@ -210,7 +210,7 @@ FRESULT fx_write (FIL* fp, const void* buff, UINT btw, UINT* bw) { res = f_write(fp, (const void*) crypt_buff, pcount, &bwl); *bw += bwl; } - + free(crypt_buff); } else res = f_write(fp, buff, btw, bw); return res; @@ -255,12 +255,12 @@ FRESULT fa_unlink (const TCHAR* path) { // special functions for access of virtual NAND SD drives bool SetupNandSdDrive(const char* path, const char* sd_path, const char* movable, int num) { char alias[128]; - + // initial checks if ((num >= NUM_ALIAS_DRV) || (num < 0)) return false; alias_drv[num] = 0; if (!sd_path || !movable || !path) return true; - + // grab the key Y from movable.sed UINT bytes_read = 0; FIL file; @@ -272,13 +272,13 @@ bool SetupNandSdDrive(const char* path, const char* sd_path, const char* movable return false; } f_close(&file); - + // build the alias path (id0) u32 sha256sum[8]; sha_quick(sha256sum, sd_keyy[num], 0x10, SHA256_MODE); snprintf(alias, 127, "%s/Nintendo 3DS/%08lX%08lX%08lX%08lX", sd_path, sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); - + // find the alias path (id1) char* id1 = alias + strnlen(alias, 127); DIR pdir; @@ -297,7 +297,7 @@ bool SetupNandSdDrive(const char* path, const char* sd_path, const char* movable } f_closedir(&pdir); if (!(*id1)) return false; - + // create the alias drive return SetupAliasDrive(path, alias, num); } @@ -307,12 +307,12 @@ bool SetupAliasDrive(const char* path, const char* alias, int num) { if ((num >= NUM_ALIAS_DRV) || (num < 0)) return false; alias_drv[num] = 0; if (!alias || !path) return true; - + // take over drive path and alias strncpy(alias_path[num], alias, 128); if (path[1] != ':') return false; alias_drv[num] = path[0]; - + return true; } diff --git a/arm9/source/filesys/support.c b/arm9/source/filesys/support.c index 16a0404..cbfc1dc 100644 --- a/arm9/source/filesys/support.c +++ b/arm9/source/filesys/support.c @@ -12,7 +12,7 @@ bool CheckSupportFile(const char* fname) // try VRAM0 first if (FindVTarFileInfo(fname, NULL)) return true; - + // try support file paths const char* base_paths[] = { SUPPORT_FILE_PATHS }; for (u32 i = 0; i < countof(base_paths); i++) { @@ -21,7 +21,7 @@ bool CheckSupportFile(const char* fname) if (fvx_stat(path, NULL) == FR_OK) return true; } - + return false; } @@ -34,7 +34,7 @@ size_t LoadSupportFile(const char* fname, void* buffer, size_t max_len) memcpy(buffer, data, len64); return (size_t) len64; } - + // try support file paths const char* base_paths[] = { SUPPORT_FILE_PATHS }; for (u32 i = 0; i < countof(base_paths); i++) { @@ -44,7 +44,7 @@ size_t LoadSupportFile(const char* fname, void* buffer, size_t max_len) if (fvx_qread(path, buffer, 0, max_len, &len32) == FR_OK) return len32; } - + return 0; } @@ -73,7 +73,7 @@ bool SaveSupportFile(const char* fname, void* buffer, size_t len) if (fvx_qwrite(path, buffer, 0, len, NULL) == FR_OK) return true; } - + return false; } @@ -102,7 +102,7 @@ bool GetSupportDir(char* path, const char* dname) if ((fvx_stat(path, &fno) == FR_OK) && (fno.fattrib & AM_DIR)) return true; } - + return false; } diff --git a/arm9/source/filesys/vff.c b/arm9/source/filesys/vff.c index f5590d8..0e13a60 100644 --- a/arm9/source/filesys/vff.c +++ b/arm9/source/filesys/vff.c @@ -151,22 +151,22 @@ FRESULT fvx_qread (const TCHAR* path, void* buff, FSIZE_t ofs, UINT btr, UINT* b FIL fp; FRESULT res; UINT brt = 0; - + res = fvx_open(&fp, path, FA_READ | FA_OPEN_EXISTING); if (res != FR_OK) return res; - + res = fvx_lseek(&fp, ofs); if (res != FR_OK) { fvx_close(&fp); return res; } - + res = fvx_read(&fp, buff, btr, &brt); fvx_close(&fp); - + if (br) *br = brt; else if ((res == FR_OK) && (brt != btr)) res = FR_DENIED; - + return res; } @@ -174,29 +174,29 @@ FRESULT fvx_qwrite (const TCHAR* path, const void* buff, FSIZE_t ofs, UINT btw, FIL fp; FRESULT res; UINT bwt = 0; - + res = fvx_open(&fp, path, FA_WRITE | FA_OPEN_ALWAYS); if (res != FR_OK) return res; - + res = fvx_lseek(&fp, ofs); if (res != FR_OK) { fvx_close(&fp); return res; } - + res = fvx_write(&fp, buff, btw, &bwt); fvx_close(&fp); - + if (bw) *bw = bwt; else if ((res == FR_OK) && (bwt != btw)) res = FR_DENIED; - + return res; } FRESULT fvx_qcreate (const TCHAR* path, UINT btc) { FIL fp; FRESULT res; - + res = fvx_open(&fp, path, FA_WRITE | FA_CREATE_ALWAYS); if (res != FR_OK) return res; @@ -212,7 +212,7 @@ FRESULT fvx_qfill (const TCHAR* path, const void* buff, UINT btb) { FRESULT res; UINT bwtt = 0; UINT fsiz = 0; - + res = fvx_open(&fp, path, FA_WRITE | FA_OPEN_EXISTING); if (res != FR_OK) return res; @@ -281,17 +281,17 @@ FRESULT fvx_rmkpath (const TCHAR* path) { FRESULT worker_fvx_runlink (TCHAR* tpath) { FILINFO fno; FRESULT res; - + // this code handles directory content deletion if ((res = fvx_stat(tpath, &fno)) != FR_OK) return res; // tpath does not exist if (fno.fattrib & AM_DIR) { // process folder contents DIR pdir; TCHAR* fname = tpath + strnlen(tpath, 255); - - + + if ((res = fa_opendir(&pdir, tpath)) != FR_OK) return res; *(fname++) = '/'; - + while (fvx_readdir(&pdir, &fno) == FR_OK) { if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0)) continue; // filter out virtual entries @@ -305,7 +305,7 @@ FRESULT worker_fvx_runlink (TCHAR* tpath) { fvx_closedir(&pdir); *(--fname) = '\0'; } - + return fvx_unlink( tpath ); } #endif @@ -344,7 +344,7 @@ FRESULT fvx_match_name(const TCHAR* path, const TCHAR* pattern) { if (fvx_match_name(path, pattern + 1) == FR_OK) return FR_OK; } } - + return FR_NO_FILE; } @@ -360,19 +360,19 @@ FRESULT fvx_findpath (TCHAR* path, const TCHAR* pattern, BYTE mode) { TCHAR* fname = strrchr(path, '/'); if (!fname) return FR_DENIED; *fname = '\0'; - + TCHAR* npattern = strrchr(pattern, '/'); if (!npattern) return FR_DENIED; npattern++; - + DIR pdir; FILINFO fno; FRESULT res; if ((res = fvx_opendir(&pdir, path)) != FR_OK) return res; - + *(fname++) = '/'; *fname = '\0'; - + while ((fvx_preaddir(&pdir, &fno, npattern) == FR_OK) && *(fno.fname)) { int cmp = strncmp(fno.fname, fname, _MAX_FN_LEN); if (((mode & FN_HIGHEST) && (cmp > 0)) || ((mode & FN_LOWEST) && (cmp < 0)) || !(*fname)) @@ -380,7 +380,7 @@ FRESULT fvx_findpath (TCHAR* path, const TCHAR* pattern, BYTE mode) { if (!(mode & (FN_HIGHEST|FN_LOWEST))) break; } fvx_closedir( &pdir ); - + return (*fname) ? FR_OK : FR_NO_PATH; } @@ -389,7 +389,7 @@ FRESULT fvx_findnopath (TCHAR* path, const TCHAR* pattern) { TCHAR* fname = strrchr(path, '/'); if (!fname) return FR_DENIED; fname++; - + TCHAR* rep[16]; u32 n_rep = 0; for (u32 i = 0; fname[i]; i++) { @@ -400,7 +400,7 @@ FRESULT fvx_findnopath (TCHAR* path, const TCHAR* pattern) { if (n_rep >= 16) return FR_DENIED; } if (!n_rep) return (fvx_stat(path, NULL) == FR_OK) ? FR_NO_PATH : FR_OK; - + while (fvx_stat(path, NULL) == FR_OK) { for (int i = n_rep - 1; (i >= 0); i--) { if (*(rep[i]) == '9') { @@ -412,7 +412,7 @@ FRESULT fvx_findnopath (TCHAR* path, const TCHAR* pattern) { } } } - + return FR_OK; } diff --git a/arm9/source/game/bdri.c b/arm9/source/game/bdri.c index 7517def..0002d24 100644 --- a/arm9/source/game/bdri.c +++ b/arm9/source/game/bdri.c @@ -105,8 +105,8 @@ static FRESULT BDRIWrite(UINT ofs, UINT btw, const void* buf) { bool CheckDBMagic(const u8* pre_header, bool tickdb) { const TitleDBPreHeader* title = (TitleDBPreHeader*) pre_header; const TickDBPreHeader* tick = (TickDBPreHeader*) pre_header; - - return (tickdb ? ((strncmp(tick->magic, "TICK", 4) == 0) && (tick->unknown1 == 1)) : + + return (tickdb ? ((strncmp(tick->magic, "TICK", 4) == 0) && (tick->unknown1 == 1)) : ((strcmp(title->magic, "NANDIDB") == 0) || (strcmp(title->magic, "NANDTDB") == 0) || (strcmp(title->magic, "TEMPIDB") == 0) || (strcmp(title->magic, "TEMPTDB") == 0))) && (strcmp((tickdb ? tick->fs_header : title->fs_header).magic, "BDRI") == 0) && @@ -133,13 +133,13 @@ static u32 GetBDRIEntrySize(const BDRIFsHeader* fs_header, const u32 fs_header_o const u32 data_offset = fs_header_offset + fs_header->data_offset; const u32 fet_offset = data_offset + fs_header->fet_start_block * fs_header->data_block_size; const u32 fht_offset = fs_header_offset + fs_header->fht_offset; - + u32 index = 0; TdbFileEntry file_entry; u64 tid_be = getbe64(title_id); u8* title_id_be = (u8*) &tid_be; const u32 hash_bucket = GetHashBucket(title_id_be, 1, fs_header->fht_bucket_count); - + if (BDRIRead(fht_offset + hash_bucket * sizeof(u32), sizeof(u32), &(file_entry.hash_bucket_next_index)) != FR_OK) return 1; @@ -147,13 +147,13 @@ static u32 GetBDRIEntrySize(const BDRIFsHeader* fs_header, const u32 fs_header_o do { if (file_entry.hash_bucket_next_index == 0) return 1; - + index = file_entry.hash_bucket_next_index; - + if (BDRIRead(fet_offset + index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &file_entry) != FR_OK) return 1; } while (memcmp(title_id_be, file_entry.title_id, 8) != 0); - + *size = file_entry.size; return 0; @@ -162,18 +162,18 @@ static u32 GetBDRIEntrySize(const BDRIFsHeader* fs_header, const u32 fs_header_o static u32 ReadBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_offset, const u8* title_id, u8* entry, const u32 expected_size) { if ((fs_header->info_offset != 0x20) || (fs_header->fat_entry_count != fs_header->data_block_count)) // Could be more thorough return 1; - + const u32 data_offset = fs_header_offset + fs_header->data_offset; const u32 fet_offset = data_offset + fs_header->fet_start_block * fs_header->data_block_size; const u32 fht_offset = fs_header_offset + fs_header->fht_offset; const u32 fat_offset = fs_header_offset + fs_header->fat_offset; - + u32 index = 0; TdbFileEntry file_entry; u64 tid_be = getbe64(title_id); u8* title_id_be = (u8*) &tid_be; const u32 hash_bucket = GetHashBucket(title_id_be, 1, fs_header->fht_bucket_count); - + if (BDRIRead(fht_offset + hash_bucket * sizeof(u32), sizeof(u32), &(file_entry.hash_bucket_next_index)) != FR_OK) return 1; @@ -181,108 +181,108 @@ static u32 ReadBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_offs do { if (file_entry.hash_bucket_next_index == 0) return 1; - + index = file_entry.hash_bucket_next_index; - + if (BDRIRead(fet_offset + index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &file_entry) != FR_OK) return 1; } while (memcmp(title_id_be, file_entry.title_id, 8) != 0); - + if (expected_size && (file_entry.size != expected_size)) return 1; - + index = file_entry.start_block_index + 1; // FAT entry index - + u32 bytes_read = 0; u32 fat_entry[2]; - + while (bytes_read < file_entry.size) { // Read the full entry, walking the FAT node chain u32 read_start = index - 1; // Data region block index u32 read_count = 0; - + if (BDRIRead(fat_offset + index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; - + if ((bytes_read == 0) && !getfatflag(fat_entry[0])) return 1; - + u32 next_index = getfatindex(fat_entry[1]); - + if (getfatflag(fat_entry[1])) { // Multi-entry node if (BDRIRead(fat_offset + (index + 1) * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; - + if (!getfatflag(fat_entry[0]) || getfatflag(fat_entry[1]) || (getfatindex(fat_entry[0]) != index) || (getfatindex(fat_entry[0]) >= getfatindex(fat_entry[1]))) return 1; - + read_count = getfatindex(fat_entry[1]) + 1 - index; } else { // Single-entry node read_count = 1; } - + index = next_index; - + u32 btr = min(file_entry.size - bytes_read, read_count * fs_header->data_block_size); if (entry && (BDRIRead(data_offset + read_start * fs_header->data_block_size, btr, entry + bytes_read) != FR_OK)) return 1; - + bytes_read += btr; } - + return 0; } static u32 RemoveBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_offset, const u8* title_id) { if ((fs_header->info_offset != 0x20) || (fs_header->fat_entry_count != fs_header->data_block_count)) // Could be more thorough return 1; - + const u32 data_offset = fs_header_offset + fs_header->data_offset; const u32 det_offset = data_offset + fs_header->det_start_block * fs_header->data_block_size; const u32 fet_offset = data_offset + fs_header->fet_start_block * fs_header->data_block_size; const u32 fht_offset = fs_header_offset + fs_header->fht_offset; const u32 fat_offset = fs_header_offset + fs_header->fat_offset; - + u32 index = 0, previous_index = 0; TdbFileEntry file_entry; u64 tid_be = getbe64(title_id); u8* title_id_be = (u8*) &tid_be; - + // Read the index of the first file entry from the directory entry table if (BDRIRead(det_offset + 0x2C, sizeof(u32), &(file_entry.next_sibling_index)) != FR_OK) return 1; - + // Find the file entry for the tid specified, fail if it doesn't exist do { previous_index = index; index = file_entry.next_sibling_index; - + if (index == 0) return 1; - + if (BDRIRead(fet_offset + index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &file_entry) != FR_OK) return 1; } while (memcmp(title_id_be, file_entry.title_id, 8) != 0); - + DummyFileEntry dummy_entry; - + // Read the 0th entry in the FET, which is always a dummy entry if (BDRIRead(fet_offset, sizeof(DummyFileEntry), &dummy_entry) != FR_OK) return 1; - + if (dummy_entry.max_entry_count != fs_header->max_file_count + 1) return 1; - + if ((BDRIWrite(fet_offset + index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &dummy_entry) != FR_OK) || (BDRIWrite(fet_offset + 0x28, sizeof(u32), &index) != FR_OK) || (BDRIWrite((previous_index == 0) ? det_offset + 0x2C : fet_offset + previous_index * sizeof(TdbFileEntry) + 0xC, sizeof(u32), &(file_entry.next_sibling_index)) != FR_OK)) return 1; - + const u32 hash_bucket = GetHashBucket(file_entry.title_id, file_entry.parent_index, fs_header->fht_bucket_count); u32 index_hash = 0; - + if (BDRIRead(fht_offset + hash_bucket * sizeof(u32), sizeof(u32), &index_hash) != FR_OK) return 1; - + if (index_hash == index) { if (BDRIWrite(fht_offset + hash_bucket * sizeof(u32), sizeof(u32), &(file_entry.hash_bucket_next_index)) != FR_OK) return 1; @@ -290,83 +290,83 @@ static u32 RemoveBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_of do { if (index_hash == 0) // This shouldn't happen if the entry was properly added break; - + if (BDRIRead(fet_offset + index_hash * sizeof(TdbFileEntry) + 0x28, sizeof(u32), &index_hash) != FR_OK) return 1; } while (index_hash != index); - + if ((index_hash != 0) && BDRIWrite(fet_offset + index_hash * sizeof(TdbFileEntry) + 0x28, sizeof(u32), &(file_entry.hash_bucket_next_index)) != FR_OK) return 1; } - + u32 fat_entry[2]; - + if (BDRIRead(fat_offset, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; - + if (getfatflag(fat_entry[1]) || (fat_entry[0] != 0)) return 1; - + u32 next_free_index = getfatindex(fat_entry[1]), fat_index = file_entry.start_block_index + 1; - + if (BDRIWrite(fat_offset + sizeof(u32), sizeof(u32), &fat_index) != FR_OK) return 1; - + fat_entry[1] = fat_index; - + do { fat_index = getfatindex(fat_entry[1]); - + if (BDRIRead(fat_offset + FAT_ENTRY_SIZE * fat_index, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; } while (getfatindex(fat_entry[1]) != 0); - + fat_entry[1] |= next_free_index; - + if ((BDRIWrite(fat_offset + fat_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) || (BDRIRead(fat_offset + next_free_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK)) return 1; - + fat_entry[0] = buildfatuv(fat_index, false); - + if (BDRIWrite(fat_offset + next_free_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; - + return 0; } static u32 AddBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_offset, const u8* title_id, const u8* entry, const u32 size, bool replace) { if ((fs_header->info_offset != 0x20) || (fs_header->fat_entry_count != fs_header->data_block_count)) // Could be more thorough return 1; - + if (!entry || !size) return 1; - + const u32 data_offset = fs_header_offset + fs_header->data_offset; const u32 det_offset = data_offset + fs_header->det_start_block * fs_header->data_block_size; const u32 fet_offset = data_offset + fs_header->fet_start_block * fs_header->data_block_size; const u32 fht_offset = fs_header_offset + fs_header->fht_offset; const u32 fat_offset = fs_header_offset + fs_header->fat_offset; const u32 size_blocks = (size / fs_header->data_block_size) + (((size % fs_header->data_block_size) == 0) ? 0 : 1); - + u32 index = 0, max_index = 0; TdbFileEntry file_entry; u64 tid_be = getbe64(title_id); u8* title_id_be = (u8*) &tid_be; bool do_replace = false; - + // Read the index of the first file entry from the directory entry table - if (BDRIRead(det_offset + 0x2C, sizeof(u32), &(file_entry.next_sibling_index)) != FR_OK) + if (BDRIRead(det_offset + 0x2C, sizeof(u32), &(file_entry.next_sibling_index)) != FR_OK) return 1; - + // Try to find the file entry for the tid specified while (file_entry.next_sibling_index != 0) { index = file_entry.next_sibling_index; - max_index = max(index, max_index); - + max_index = max(index, max_index); + if (BDRIRead(fet_offset + index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &file_entry) != FR_OK) return 1; - + // If an entry for the tid already existed that is already the specified size and replace was specified, just replace the existing entry if (memcmp(title_id_be, file_entry.title_id, 8) == 0) { if (!replace || (file_entry.size != size)) return 1; @@ -376,10 +376,10 @@ static u32 AddBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_offse } } } - + u32 fat_entry[2]; u32 fat_index = 0; - + if (!do_replace) { if (BDRIRead(fat_offset, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; @@ -476,48 +476,48 @@ static u32 AddBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_offse if (BDRIWrite(fat_offset + previous_free_index * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; } else fat_index = file_entry.start_block_index + 1; - + u32 bytes_written = 0, fat_index_write = fat_index; - + while (bytes_written < size) { // Write the full entry, walking the FAT node chain // Can't assume contiguity here, because we might be replacing an existing entry u32 write_start = fat_index_write - 1; // Data region block index u32 write_count = 0; - + if (BDRIRead(fat_offset + fat_index_write * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; - + if ((bytes_written == 0) && !getfatflag(fat_entry[0])) return 1; - + u32 next_index = getfatindex(fat_entry[1]); - + if (getfatflag(fat_entry[1])) { // Multi-entry node if (BDRIRead(fat_offset + (fat_index_write + 1) * FAT_ENTRY_SIZE, FAT_ENTRY_SIZE, fat_entry) != FR_OK) return 1; - + if (!getfatflag(fat_entry[0]) || getfatflag(fat_entry[1]) || (getfatindex(fat_entry[0]) != fat_index_write) || (getfatindex(fat_entry[0]) >= getfatindex(fat_entry[1]))) return 1; - + write_count = getfatindex(fat_entry[1]) + 1 - fat_index_write; } else { // Single-entry node write_count = 1; } - + fat_index_write = next_index; - + u32 btw = min(size - bytes_written, write_count * fs_header->data_block_size); if (BDRIWrite(data_offset + write_start * fs_header->data_block_size, btw, entry + bytes_written) != FR_OK) return 1; - + bytes_written += btw; } - + if (!do_replace) { DummyFileEntry dummy_entry; // Read the 0th entry in the FET, which is always a dummy entry - if (BDRIRead(fet_offset, sizeof(DummyFileEntry), &dummy_entry) != FR_OK) + if (BDRIRead(fet_offset, sizeof(DummyFileEntry), &dummy_entry) != FR_OK) return 1; if (dummy_entry.max_entry_count != fs_header->max_file_count + 1) @@ -559,83 +559,83 @@ static u32 AddBDRIEntry(const BDRIFsHeader* fs_header, const u32 fs_header_offse if (BDRIWrite(fet_offset + index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &file_entry) != FR_OK) return 1; } - + return 0; } static u32 GetNumBDRIEntries(const BDRIFsHeader* fs_header, const u32 fs_header_offset) { if ((fs_header->info_offset != 0x20) || (fs_header->fat_entry_count != fs_header->data_block_count)) // Could be more thorough - return 0; - + return 0; + const u32 data_offset = fs_header_offset + fs_header->data_offset; const u32 det_offset = data_offset + fs_header->det_start_block * fs_header->data_block_size; const u32 fet_offset = data_offset + fs_header->fet_start_block * fs_header->data_block_size; - + u32 num_entries = 0; TdbFileEntry file_entry; - + // Read the index of the first file entry from the directory entry table if (BDRIRead(det_offset + 0x2C, sizeof(u32), &(file_entry.next_sibling_index)) != FR_OK) return 0; - + while (file_entry.next_sibling_index != 0) { num_entries++; if (BDRIRead(fet_offset + file_entry.next_sibling_index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &file_entry) != FR_OK) return 0; } - + return num_entries; } static u32 ListBDRIEntryTitleIDs(const BDRIFsHeader* fs_header, const u32 fs_header_offset, u8* title_ids, u32 max_title_ids) { if ((fs_header->info_offset != 0x20) || (fs_header->fat_entry_count != fs_header->data_block_count)) return 0; - + const u32 data_offset = fs_header_offset + fs_header->data_offset; const u32 det_offset = data_offset + fs_header->det_start_block * fs_header->data_block_size; const u32 fet_offset = data_offset + fs_header->fet_start_block * fs_header->data_block_size; - + u32 num_entries = 0; TdbFileEntry file_entry; - + for (u32 i = 0; i < max_title_ids; i++) memset(title_ids, 0, max_title_ids * 8); - + // Read the index of the first file entry from the directory entry table if (BDRIRead(det_offset + 0x2C, sizeof(u32), &(file_entry.next_sibling_index)) != FR_OK) return 1; - + while ((file_entry.next_sibling_index != 0) && (num_entries < max_title_ids)) { if (BDRIRead(fet_offset + file_entry.next_sibling_index * sizeof(TdbFileEntry), sizeof(TdbFileEntry), &file_entry) != FR_OK) return 1; - + u64 tid_be = getbe64(file_entry.title_id); memcpy(title_ids + num_entries * 8, (u8*) &tid_be, 8); - + num_entries++; } - + return 0; } u32 GetNumTitleInfoEntries(const char* path) { FIL file; TitleDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 0; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TitleDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, false)) { fvx_close(bdrifp); bdrifp = NULL; return 0; } - + u32 num = GetNumBDRIEntries(&(pre_header.fs_header), sizeof(TitleDBPreHeader) - sizeof(BDRIFsHeader)); - + fvx_close(bdrifp); bdrifp = NULL; return num; @@ -644,12 +644,12 @@ u32 GetNumTitleInfoEntries(const char* path) { u32 GetNumTickets(const char* path) { FIL file; TickDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 0; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TickDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, true)) { fvx_close(bdrifp); @@ -658,7 +658,7 @@ u32 GetNumTickets(const char* path) { } u32 num = GetNumBDRIEntries(&(pre_header.fs_header), sizeof(TickDBPreHeader) - sizeof(BDRIFsHeader)); - + fvx_close(bdrifp); bdrifp = NULL; return num; @@ -667,12 +667,12 @@ u32 GetNumTickets(const char* path) { u32 ListTitleInfoEntryTitleIDs(const char* path, u8* title_ids, u32 max_title_ids) { FIL file; TitleDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TitleDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, false) || (ListBDRIEntryTitleIDs(&(pre_header.fs_header), sizeof(TitleDBPreHeader) - sizeof(BDRIFsHeader), title_ids, max_title_ids) != 0)) { @@ -680,7 +680,7 @@ u32 ListTitleInfoEntryTitleIDs(const char* path, u8* title_ids, u32 max_title_id bdrifp = NULL; return 1; } - + fvx_close(bdrifp); bdrifp = NULL; return 0; @@ -689,12 +689,12 @@ u32 ListTitleInfoEntryTitleIDs(const char* path, u8* title_ids, u32 max_title_id u32 ListTicketTitleIDs(const char* path, u8* title_ids, u32 max_title_ids) { FIL file; TickDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TickDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, true) || (ListBDRIEntryTitleIDs(&(pre_header.fs_header), sizeof(TickDBPreHeader) - sizeof(BDRIFsHeader), title_ids, max_title_ids) != 0)) { @@ -702,7 +702,7 @@ u32 ListTicketTitleIDs(const char* path, u8* title_ids, u32 max_title_ids) { bdrifp = NULL; return 1; } - + fvx_close(bdrifp); bdrifp = NULL; return 0; @@ -711,12 +711,12 @@ u32 ListTicketTitleIDs(const char* path, u8* title_ids, u32 max_title_ids) { u32 ReadTitleInfoEntryFromDB(const char* path, const u8* title_id, TitleInfoEntry* tie) { FIL file; TitleDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TitleDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, false) || (ReadBDRIEntry(&(pre_header.fs_header), sizeof(TitleDBPreHeader) - sizeof(BDRIFsHeader), title_id, (u8*) tie, @@ -725,7 +725,7 @@ u32 ReadTitleInfoEntryFromDB(const char* path, const u8* title_id, TitleInfoEntr bdrifp = NULL; return 1; } - + fvx_close(bdrifp); bdrifp = NULL; return 0; @@ -739,13 +739,13 @@ u32 ReadTicketFromDB(const char* path, const u8* title_id, Ticket** ticket) { if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TickDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, true) || (GetBDRIEntrySize(&(pre_header.fs_header), sizeof(TickDBPreHeader) - sizeof(BDRIFsHeader), title_id, &entry_size) != 0) || - entry_size < sizeof(TicketEntry) + 0x14 || + entry_size < sizeof(TicketEntry) + 0x14 || (te = (TicketEntry*)malloc(entry_size), te == NULL) || (ReadBDRIEntry(&(pre_header.fs_header), sizeof(TickDBPreHeader) - sizeof(BDRIFsHeader), title_id, (u8*) te, entry_size) != 0)) { @@ -754,15 +754,15 @@ u32 ReadTicketFromDB(const char* path, const u8* title_id, Ticket** ticket) { bdrifp = NULL; return 1; } - + fvx_close(bdrifp); bdrifp = NULL; - + if (te->ticket_size != GetTicketSize(&te->ticket)) { free(te); return 1; } - + if (ticket) { u32 size = te->ticket_size; memmove(te, &te->ticket, size); // recycle this memory, instead of allocating another @@ -771,7 +771,7 @@ u32 ReadTicketFromDB(const char* path, const u8* title_id, Ticket** ticket) { *ticket = tik; return 0; } - + free(te); return 0; } @@ -779,12 +779,12 @@ u32 ReadTicketFromDB(const char* path, const u8* title_id, Ticket** ticket) { u32 RemoveTitleInfoEntryFromDB(const char* path, const u8* title_id) { FIL file; TitleDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) return 1; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TitleDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, false) || (RemoveBDRIEntry(&(pre_header.fs_header), sizeof(TitleDBPreHeader) - sizeof(BDRIFsHeader), title_id) != 0)) { @@ -792,7 +792,7 @@ u32 RemoveTitleInfoEntryFromDB(const char* path, const u8* title_id) { bdrifp = NULL; return 1; } - + fvx_close(bdrifp); bdrifp = NULL; return 0; @@ -801,12 +801,12 @@ u32 RemoveTitleInfoEntryFromDB(const char* path, const u8* title_id) { u32 RemoveTicketFromDB(const char* path, const u8* title_id) { FIL file; TickDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) return 1; - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TickDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, true) || (RemoveBDRIEntry(&(pre_header.fs_header), sizeof(TickDBPreHeader) - sizeof(BDRIFsHeader), title_id) != 0)) { @@ -814,7 +814,7 @@ u32 RemoveTicketFromDB(const char* path, const u8* title_id) { bdrifp = NULL; return 1; } - + fvx_close(&file); bdrifp = NULL; return 0; @@ -823,13 +823,13 @@ u32 RemoveTicketFromDB(const char* path, const u8* title_id) { u32 AddTitleInfoEntryToDB(const char* path, const u8* title_id, const TitleInfoEntry* tie, bool replace) { FIL file; TitleDBPreHeader pre_header; - + if (fvx_open(&file, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) return 1; - + bdrifp = &file; - - if ((BDRIRead(0, sizeof(TitleDBPreHeader), &pre_header) != FR_OK) || + + if ((BDRIRead(0, sizeof(TitleDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, false) || (AddBDRIEntry(&(pre_header.fs_header), sizeof(TitleDBPreHeader) - sizeof(BDRIFsHeader), title_id, (const u8*) tie, sizeof(TitleInfoEntry), replace) != 0)) { @@ -837,7 +837,7 @@ u32 AddTitleInfoEntryToDB(const char* path, const u8* title_id, const TitleInfoE bdrifp = NULL; return 1; } - + fvx_close(bdrifp); bdrifp = NULL; return 0; @@ -847,7 +847,7 @@ u32 AddTicketToDB(const char* path, const u8* title_id, const Ticket* ticket, bo FIL file; TickDBPreHeader pre_header; u32 entry_size = sizeof(TicketEntry) + GetTicketContentIndexSize(ticket); - + TicketEntry* te = (TicketEntry*)malloc(entry_size); if (!te) { return 1; @@ -860,9 +860,9 @@ u32 AddTicketToDB(const char* path, const u8* title_id, const Ticket* ticket, bo free(te); return 1; } - + bdrifp = &file; - + if ((BDRIRead(0, sizeof(TickDBPreHeader), &pre_header) != FR_OK) || !CheckDBMagic((u8*) &pre_header, true) || (AddBDRIEntry(&(pre_header.fs_header), sizeof(TickDBPreHeader) - sizeof(BDRIFsHeader), title_id, diff --git a/arm9/source/game/boss.c b/arm9/source/game/boss.c index e10396e..601c6f1 100644 --- a/arm9/source/game/boss.c +++ b/arm9/source/game/boss.c @@ -7,7 +7,7 @@ u32 CheckBossHash(BossHeader* boss, bool encrypted) { u8 hash_area[0x14] __attribute__((aligned(4))) = { 0 }; u8 boss_sha256[0x20]; u8 l_sha256[0x20]; - + // calculate hash memcpy(hash_area, ((u8*) boss) + 0x28, 0x12); memcpy(boss_sha256, boss->hash_header, 0x20); @@ -16,13 +16,13 @@ u32 CheckBossHash(BossHeader* boss, bool encrypted) { CryptBoss(boss_sha256, 0x28 + 0x12, 0x20, boss); } sha_quick(l_sha256, hash_area, 0x14, SHA256_MODE); - + return (memcmp(boss_sha256, l_sha256, 0x20) == 0) ? 0 : 1; } u32 ValidateBossHeader(BossHeader* header, u32 fsize) { u8 boss_magic[] = { BOSS_MAGIC }; - + // base checks if ((memcmp(header->magic, boss_magic, sizeof(boss_magic)) != 0) || (fsize && (fsize != getbe32(header->filesize))) || @@ -31,12 +31,12 @@ u32 ValidateBossHeader(BossHeader* header, u32 fsize) { (getbe16(header->cnthdr_hash_type) != 0x0002) || (getbe16(header->cnthdr_rsa_size) != 0x0002)) return 1; - + // hash check if ((CheckBossHash(header, false) != 0) && (CheckBossHash(header, true) != 0)) return 1; - + return 0; } @@ -59,14 +59,14 @@ u32 CryptBoss(void* data, u32 offset, u32 size, BossHeader* boss) { size -= 0x28 - offset; offset = 0x28; } - + // decrypt BOSS data u8 ctr[16] = { 0 }; memcpy(ctr, boss->ctr12, 12); ctr[15] = 0x01; use_aeskey(0x38); ctr_decrypt_byte(data, data, size, offset - 0x28, AES_CNT_CTRNAND_MODE, ctr); - + return 0; } @@ -76,7 +76,7 @@ u32 CryptBossSequential(void* data, u32 offset, u32 size) { // unexpected results otherwise static BossHeader boss = { 0 }; static BossHeader* bossptr = NULL; - + // fetch boss header from data if ((offset == 0) && (size >= sizeof(BossHeader))) { bossptr = NULL; @@ -87,9 +87,9 @@ u32 CryptBossSequential(void* data, u32 offset, u32 size) { return 1; bossptr = &boss; } - + // safety check, boss pointer if (!bossptr) return 1; - + return CryptBoss(data, offset, size, bossptr); } diff --git a/arm9/source/game/boss.h b/arm9/source/game/boss.h index 9eca1f2..4fa8bbf 100644 --- a/arm9/source/game/boss.h +++ b/arm9/source/game/boss.h @@ -14,7 +14,7 @@ typedef struct { // actual BOSS header u8 magic[8]; // "boss" + 0x00010001, see above - u8 filesize[4]; // big endian + u8 filesize[4]; // big endian u8 release_date[8]; u8 unknown0[2]; // always 0x0001 u8 padding[2]; @@ -27,7 +27,7 @@ typedef struct { u8 hash_header[0x20]; u8 signature_header[0x100]; // payload header, first 0x1C byte used for hash (0x15A) - u8 programId[8]; + u8 programId[8]; u8 unknown2[4]; // typically zero u8 data_type[4]; u8 size_payload[4]; diff --git a/arm9/source/game/cia.c b/arm9/source/game/cia.c index e421089..630e838 100644 --- a/arm9/source/game/cia.c +++ b/arm9/source/game/cia.c @@ -18,20 +18,20 @@ u32 ValidateCiaHeader(CiaHeader* header) { u32 GetCiaInfo(CiaInfo* info, CiaHeader* header) { if ((u8*) info != (u8*) header) memcpy(info, header, 0x20); // take over first 0x20 byte - + info->offset_cert = align(header->size_header, 64); info->offset_ticket = info->offset_cert + align(header->size_cert, 64); info->offset_tmd = info->offset_ticket + align(header->size_ticket, 64); info->offset_content = info->offset_tmd + align(header->size_tmd, 64); info->offset_meta = (header->size_meta) ? info->offset_content + align(header->size_content, 64) : 0; info->offset_content_list = info->offset_tmd + sizeof(TitleMetaData); - + info->size_content_list = info->size_tmd - sizeof(TitleMetaData); info->size_cia = (header->size_meta) ? info->offset_meta + info->size_meta : info->offset_content + info->size_content; - + info->max_contents = (info->size_tmd - sizeof(TitleMetaData)) / sizeof(TmdContentChunk); - + return 0; } @@ -58,7 +58,7 @@ u32 BuildCiaCert(u8* ciacert) { 0xFB, 0xD2, 0xC0, 0x47, 0x95, 0xB9, 0x4C, 0xC8, 0x0B, 0x64, 0x58, 0x96, 0xF6, 0x61, 0x0F, 0x52, 0x18, 0x83, 0xAF, 0xE0, 0xF4, 0xE5, 0x62, 0xBA, 0x69, 0xEE, 0x72, 0x2A, 0xC2, 0x4E, 0x95, 0xB3 }; - + // open certs.db file on SysNAND FIL db; UINT bytes_read; @@ -74,13 +74,13 @@ u32 BuildCiaCert(u8* ciacert) { f_lseek(&db, 0x3C10); f_read(&db, ciacert + 0x700, 0x300, &bytes_read); f_close(&db); - + // check the certificate hash u8 cert_hash[0x20]; sha_quick(cert_hash, ciacert, CIA_CERT_SIZE, SHA256_MODE); if (memcmp(cert_hash, IS_DEVKIT ? cert_hash_expected_dev : cert_hash_expected, 0x20) != 0) return 1; - + return 0; } diff --git a/arm9/source/game/codelzss.c b/arm9/source/game/codelzss.c index c433175..d740547 100644 --- a/arm9/source/game/codelzss.c +++ b/arm9/source/game/codelzss.c @@ -16,10 +16,10 @@ typedef struct { u32 GetCodeLzssUncompressedSize(void* footer, u32 comp_size) { if (comp_size < sizeof(CodeLzssFooter)) return 0; - + CodeLzssFooter* f = (CodeLzssFooter*) footer; if ((CODE_COMP_SIZE(f) > comp_size) || (CODE_COMP_END(f) < 0)) return 0; - + return CODE_DEC_SIZE(f) + (comp_size - CODE_COMP_SIZE(f)); } @@ -27,22 +27,22 @@ u32 GetCodeLzssUncompressedSize(void* footer, u32 comp_size) { u32 DecompressCodeLzss(u8* code, u32* code_size, u32 max_size) { u8* data_start = code; u8* comp_start = data_start; - + // get footer, fix comp_start offset if ((*code_size < sizeof(CodeLzssFooter)) || (*code_size > max_size)) return 1; CodeLzssFooter* footer = (CodeLzssFooter*) (void*) (data_start + *code_size - sizeof(CodeLzssFooter)); if (CODE_COMP_SIZE(footer) <= *code_size) comp_start += *code_size - CODE_COMP_SIZE(footer); else return 1; - + // more sanity checks if ((CODE_COMP_END(footer) < 0) || (CODE_DEC_SIZE(footer) > max_size)) return 1; // not reverse LZSS compressed code or too big uncompressed - + // set pointers u8* data_end = (u8*) comp_start + CODE_DEC_SIZE(footer); u8* ptr_in = (u8*) comp_start + CODE_COMP_END(footer); u8* ptr_out = data_end; - + // main decompression loop while ((ptr_in > comp_start) && (ptr_out > comp_start)) { if (!ShowProgress(data_end - ptr_out, data_end - data_start, "Decompressing .code...")) { @@ -50,17 +50,17 @@ u32 DecompressCodeLzss(u8* code, u32* code_size, u32 max_size) { ShowProgress(0, data_end - data_start, "Decompressing .code..."); ShowProgress(data_end - ptr_out, data_end - data_start, "Decompressing .code..."); } - + // sanity check if (ptr_out < ptr_in) return 1; - + // read and process control byte u8 ctrlbyte = *(--ptr_in); for (int i = 7; i >= 0; i--) { // end conditions met? if ((ptr_in <= comp_start) || (ptr_out <= comp_start)) break; - + // process control byte if ((ctrlbyte >> i) & 0x1) { // control bit set, read segment code @@ -69,11 +69,11 @@ u32 DecompressCodeLzss(u8* code, u32* code_size, u32 max_size) { if (ptr_in < comp_start) return 1; // corrupted code u32 seg_off = CODE_SEG_OFFSET(seg_code); u32 seg_len = CODE_SEG_SIZE(seg_code); - + // sanity check for output pointer if ((ptr_out - seg_len < comp_start) || (ptr_out + seg_off >= data_end)) return 1; - + // copy data to the correct place for (u32 c = 0; c < seg_len; c++) { u8 byte = *(ptr_out + seg_off); @@ -83,17 +83,17 @@ u32 DecompressCodeLzss(u8* code, u32* code_size, u32 max_size) { // sanity check for both pointers if ((ptr_out == comp_start) || (ptr_in == comp_start)) return 1; - + // control bit not set, copy byte verbatim *(--ptr_out) = *(--ptr_in); } } } - + // check pointers if ((ptr_in != comp_start) || (ptr_out != comp_start)) return 1; - + // all fine if arriving here - return the result *code_size = data_end - data_start; return 0; @@ -116,7 +116,7 @@ void initTable(sCompressInfo* a_pInfo, void* a_pWork) { a_pInfo->ReversedOffsetTable = (s16*)(a_pWork) + 4098; a_pInfo->ByteTable = (s16*)(a_pWork) + 4098 + 4098; a_pInfo->EndTable = (s16*)(a_pWork) + 4098 + 4098 + 256; - + for (int i = 0; i < 256; i++) { a_pInfo->ByteTable[i] = -1; a_pInfo->EndTable[i] = -1; @@ -127,35 +127,35 @@ int search(sCompressInfo* a_pInfo, const u8* a_pSrc, int* a_nOffset, int a_nMaxS if (a_nMaxSize < 3) { return 0; } - + const u8* pSearch = NULL; int nSize = 2; const u16 uWindowPos = a_pInfo->WindowPos; const u16 uWindowLen = a_pInfo->WindowLen; s16* pReversedOffsetTable = a_pInfo->ReversedOffsetTable; - + for (s16 nOffset = a_pInfo->EndTable[*(a_pSrc - 1)]; nOffset != -1; nOffset = pReversedOffsetTable[nOffset]) { if (nOffset < uWindowPos) { pSearch = a_pSrc + uWindowPos - nOffset; } else { pSearch = a_pSrc + uWindowLen + uWindowPos - nOffset; } - + if (pSearch - a_pSrc < 3) { continue; } - + if (*(pSearch - 2) != *(a_pSrc - 2) || *(pSearch - 3) != *(a_pSrc - 3)) { continue; } - + int nMaxSize = (int)((s64)min(a_nMaxSize, pSearch - a_pSrc)); int nCurrentSize = 3; - + while (nCurrentSize < nMaxSize && *(pSearch - nCurrentSize - 1) == *(a_pSrc - nCurrentSize - 1)) { nCurrentSize++; } - + if (nCurrentSize > nSize) { nSize = nCurrentSize; *a_nOffset = (int)(pSearch - a_pSrc); @@ -164,11 +164,11 @@ int search(sCompressInfo* a_pInfo, const u8* a_pSrc, int* a_nOffset, int a_nMaxS } } } - + if (nSize < 3) { return 0; } - + return nSize; } @@ -181,33 +181,33 @@ void slideByte(sCompressInfo* a_pInfo, const u8* a_pSrc) { s16* pReversedOffsetTable = a_pInfo->ReversedOffsetTable; s16* pByteTable = a_pInfo->ByteTable; s16* pEndTable = a_pInfo->EndTable; - + if (uWindowLen == 4098) { u8 uOutData = *(a_pSrc + 4097); - + if ((pByteTable[uOutData] = pOffsetTable[pByteTable[uOutData]]) == -1) { pEndTable[uOutData] = -1; } else { pReversedOffsetTable[pByteTable[uOutData]] = -1; } - + uInsertOffset = uWindowPos; } else { uInsertOffset = uWindowLen; } - + s16 nOffset = pEndTable[uInData]; - + if (nOffset == -1) { pByteTable[uInData] = uInsertOffset; } else { pOffsetTable[nOffset] = uInsertOffset; } - + pEndTable[uInData] = uInsertOffset; pOffsetTable[uInsertOffset] = -1; pReversedOffsetTable[uInsertOffset] = nOffset; - + if (uWindowLen == 4098) { a_pInfo->WindowPos = (uWindowPos + 1) % 4098; } else { @@ -228,19 +228,19 @@ s64 alignBytes(s64 a_nData, s64 a_nAlignment) { bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_pCompressed, u32* a_uCompressedSize) { const int s_nCompressWorkSize = (4098 + 4098 + 256 + 256) * sizeof(s16); bool bResult = true; - + if (a_uUncompressedSize > sizeof(CodeLzssFooter) && *a_uCompressedSize >= a_uUncompressedSize) { u8* pWork = malloc(s_nCompressWorkSize * sizeof(u8)); if (!pWork) return false; - + do { sCompressInfo info; initTable(&info, pWork); - + const int nMaxSize = 0xF + 3; const u8* pSrc = a_pUncompressed + a_uUncompressedSize; u8* pDest = a_pCompressed + a_uUncompressedSize; - + while (pSrc - a_pUncompressed > 0 && pDest - a_pCompressed > 0) { if (!ShowProgress((u32)(a_pUncompressed + a_uUncompressedSize - pSrc), a_uUncompressedSize, "Compressing .code...")) { if (ShowPrompt(true, "Compressing .code...\nB button detected. Cancel?")) { @@ -250,20 +250,20 @@ bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_ ShowProgress(0, a_uUncompressedSize, "Compressing .code..."); ShowProgress((u32)(a_pUncompressed + a_uUncompressedSize - pSrc), a_uUncompressedSize, "Compressing .code..."); } - + u8* pFlag = --pDest; *pFlag = 0; - + for (int i = 0; i < 8; i++) { int nOffset = 0; int nSize = search(&info, pSrc, &nOffset, (int)((s64)min((s64)min(nMaxSize, pSrc - a_pUncompressed), a_pUncompressed + a_uUncompressedSize - pSrc))); - + if (nSize < 3) { if (pDest - a_pCompressed < 1) { bResult = false; break; } - + slide(&info, pSrc, 1); *--pDest = *--pSrc; } else { @@ -271,7 +271,7 @@ bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_ bResult = false; break; } - + *pFlag |= 0x80 >> i; slide(&info, pSrc, nSize); pSrc -= nSize; @@ -279,29 +279,29 @@ bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_ *--pDest = (nSize << 4 & 0xF0) | ((nOffset - 3) >> 8 & 0x0F); *--pDest = (nOffset - 3) & 0xFF; } - + if (pSrc - a_pUncompressed <= 0) { break; } } - + if (!bResult) { break; } } - + if (!bResult) { break; } - + *a_uCompressedSize = (u32)(a_pCompressed + a_uUncompressedSize - pDest); } while (false); - + free(pWork); } else { bResult = false; } - + if (bResult) { u32 uOrigSize = a_uUncompressedSize; u8* pCompressBuffer = a_pCompressed + a_uUncompressedSize - *a_uCompressedSize; @@ -309,10 +309,10 @@ bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_ u32 uOrigSafe = 0; u32 uCompressSafe = 0; bool bOver = false; - + while (uOrigSize > 0) { u8 uFlag = pCompressBuffer[--uCompressBufferSize]; - + for (int i = 0; i < 8; i++) { if ((uFlag << i & 0x80) == 0) { uCompressBufferSize--; @@ -321,7 +321,7 @@ bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_ int nSize = (pCompressBuffer[--uCompressBufferSize] >> 4 & 0x0F) + 3; uCompressBufferSize--; uOrigSize -= nSize; - + if (uOrigSize < uCompressBufferSize) { uOrigSafe = uOrigSize; uCompressSafe = uCompressBufferSize; @@ -329,24 +329,24 @@ bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_ break; } } - + if (uOrigSize <= 0) { break; } } - + if (bOver) { break; } } - + u32 uCompressedSize = *a_uCompressedSize - uCompressSafe; u32 uPadOffset = uOrigSafe + uCompressedSize; u32 uCompFooterOffset = (u32)(alignBytes(uPadOffset, 4)); *a_uCompressedSize = uCompFooterOffset + sizeof(CodeLzssFooter); u32 uTop = *a_uCompressedSize - uOrigSafe; u32 uBottom = *a_uCompressedSize - uPadOffset; - + if (*a_uCompressedSize >= a_uUncompressedSize || uTop > 0xFFFFFF) { bResult = false; } else { @@ -358,6 +358,6 @@ bool CompressCodeLzss(const u8* a_pUncompressed, u32 a_uUncompressedSize, u8* a_ pCompFooter->addsize_dec = a_uUncompressedSize - *a_uCompressedSize; } } - + return bResult; } diff --git a/arm9/source/game/disadiff.c b/arm9/source/game/disadiff.c index f3814f5..295258c 100644 --- a/arm9/source/game/disadiff.c +++ b/arm9/source/game/disadiff.c @@ -107,13 +107,13 @@ inline static u32 DisaDiffSize(const TCHAR* path) { inline static FRESULT DisaDiffOpen(const TCHAR* path) { FRESULT res = FR_OK; - + ddfp = NULL; if (path) { res = fvx_open(&ddfile, path, FA_READ | FA_WRITE | FA_OPEN_EXISTING); if (res == FR_OK) ddfp = &ddfile; } else if (!GetMountState()) res = FR_DENIED; - + return res; } @@ -164,16 +164,16 @@ u32 GetDisaDiffRWInfo(const char* path, DisaDiffRWInfo* info, bool partitionB) { static const u8 ivfc_magic[] = { IVFC_MAGIC }; static const u8 dpfs_magic[] = { DPFS_MAGIC }; static const u8 difi_magic[] = { DIFI_MAGIC }; - + // reset reader info memset(info, 0x00, sizeof(DisaDiffRWInfo)); - + // get file size, header at header offset u32 file_size = DisaDiffSize(path); u8 header[0x100]; if (DisaDiffQRead(path, header, 0x100, 0x100) != FR_OK) return 1; - + // DISA/DIFF header: find partition offset & size and DIFI descriptor u32 offset_partition = 0; u32 size_partition = 0; @@ -207,22 +207,22 @@ u32 GetDisaDiffRWInfo(const char* path, DisaDiffRWInfo* info, bool partitionB) { } else { return 1; } - + // check the output so far if (!offset_difi || (offset_difi + sizeof(DifiStruct) > file_size) || (offset_partition + size_partition > file_size)) return 1; - + info->offset_difi = offset_difi; // read DIFI struct from file const DifiStruct difis; if (DisaDiffQRead(path, (DifiStruct*) &difis, offset_difi, sizeof(DifiStruct)) != FR_OK) return 1; - + if ((memcmp(difis.difi.magic, difi_magic, 8) != 0) || (memcmp(difis.ivfc.magic, ivfc_magic, 8) != 0) || (memcmp(difis.dpfs.magic, dpfs_magic, 8) != 0)) return 1; - + // check & get data from DIFI header const DifiHeader* difi = &(difis.difi); if ((difi->offset_ivfc != sizeof(DifiHeader)) || @@ -232,12 +232,12 @@ u32 GetDisaDiffRWInfo(const char* path, DisaDiffRWInfo* info, bool partitionB) { (difi->offset_hash != difi->offset_dpfs + difi->size_dpfs) || (difi->size_hash < 0x20)) return 1; - + info->dpfs_lvl1_selector = difi->dpfs_lvl1_selector; info->ivfc_use_extlvl4 = difi->ivfc_use_extlvl4; info->offset_ivfc_lvl4 = (u32) (offset_partition + difi->ivfc_offset_extlvl4); info->offset_master_hash = (u32) difi->offset_hash; - + // check & get data from DPFS descriptor const DpfsDescriptor* dpfs = &(difis.dpfs); if ((dpfs->offset_lvl1 + dpfs->size_lvl1 > dpfs->offset_lvl2) || @@ -246,7 +246,7 @@ u32 GetDisaDiffRWInfo(const char* path, DisaDiffRWInfo* info, bool partitionB) { (2 > dpfs->log_lvl2) || (dpfs->log_lvl2 > dpfs->log_lvl3) || !dpfs->size_lvl1 || !dpfs->size_lvl2 || !dpfs->size_lvl3) return 1; - + info->offset_dpfs_lvl1 = (u32) (offset_partition + dpfs->offset_lvl1); info->offset_dpfs_lvl2 = (u32) (offset_partition + dpfs->offset_lvl2); info->offset_dpfs_lvl3 = (u32) (offset_partition + dpfs->offset_lvl3); @@ -255,7 +255,7 @@ u32 GetDisaDiffRWInfo(const char* path, DisaDiffRWInfo* info, bool partitionB) { info->size_dpfs_lvl3 = (u32) dpfs->size_lvl3; info->log_dpfs_lvl2 = (u32) dpfs->log_lvl2; info->log_dpfs_lvl3 = (u32) dpfs->log_lvl3; - + // check & get data from IVFC descriptor const IvfcDescriptor* ivfc = &(difis.ivfc); if ((ivfc->size_hash != difi->size_hash) || @@ -264,16 +264,16 @@ u32 GetDisaDiffRWInfo(const char* path, DisaDiffRWInfo* info, bool partitionB) { (ivfc->offset_lvl2 + ivfc->size_lvl2 > ivfc->offset_lvl3) || (ivfc->offset_lvl3 + ivfc->size_lvl3 > dpfs->size_lvl3)) return 1; - + if (!info->ivfc_use_extlvl4) { if ((ivfc->offset_lvl3 + ivfc->size_lvl3 > ivfc->offset_lvl4) || (ivfc->offset_lvl4 + ivfc->size_lvl4 > dpfs->size_lvl3)) return 1; - + info->offset_ivfc_lvl4 = (u32) ivfc->offset_lvl4; } else if (info->offset_ivfc_lvl4 + ivfc->size_lvl4 > offset_partition + size_partition) return 1; - + info->log_ivfc_lvl1 = (u32) ivfc->log_lvl1; info->log_ivfc_lvl2 = (u32) ivfc->log_lvl2; info->log_ivfc_lvl3 = (u32) ivfc->log_lvl3; @@ -285,7 +285,7 @@ u32 GetDisaDiffRWInfo(const char* path, DisaDiffRWInfo* info, bool partitionB) { info->size_ivfc_lvl2 = (u32) ivfc->size_lvl2; info->size_ivfc_lvl3 = (u32) ivfc->size_lvl3; info->size_ivfc_lvl4 = (u32) ivfc->size_lvl4; - + return 0; } @@ -293,31 +293,31 @@ u32 BuildDisaDiffDpfsLvl2Cache(const char* path, const DisaDiffRWInfo* info, u8* const u32 min_cache_bits = (info->size_dpfs_lvl3 + (1 << info->log_dpfs_lvl3) - 1) >> info->log_dpfs_lvl3; const u32 min_cache_size = ((min_cache_bits + 31) >> (3 + 2)) << 2; const u32 offset_lvl1 = info->offset_dpfs_lvl1 + ((info->dpfs_lvl1_selector) ? info->size_dpfs_lvl1 : 0); - + // safety (this still assumes all the checks from GetDisaDiffRWInfo()) if ((cache_size < min_cache_size) || (min_cache_size > info->size_dpfs_lvl2) || (min_cache_size > (info->size_dpfs_lvl1 << (3 + info->log_dpfs_lvl2)))) { return 1; } - + // allocate memory u8* lvl1 = (u8*) malloc(info->size_dpfs_lvl1); if (!lvl1) return 1; // this is never more than 8 byte in reality -___- - + // open file pointer if (DisaDiffOpen(path) != FR_OK) { free(lvl1); return 1; } - + // read lvl1 u32 ret = 0; if ((ret != 0) || DisaDiffRead(lvl1, info->size_dpfs_lvl1, offset_lvl1)) ret = 1; - + // read full lvl2_0 to cache if ((ret != 0) || DisaDiffRead(cache, info->size_dpfs_lvl2, info->offset_dpfs_lvl2)) ret = 1; - + // cherry-pick lvl2_1 u32 log_lvl2 = info->log_dpfs_lvl2; u32 offset_lvl2_1 = info->offset_dpfs_lvl2 + info->size_dpfs_lvl2; @@ -330,7 +330,7 @@ u32 BuildDisaDiffDpfsLvl2Cache(const char* path, const DisaDiffRWInfo* info, u8* } } } - + ((DisaDiffRWInfo*) info)->dpfs_lvl2_cache = cache; free(lvl1); DisaDiffClose(); @@ -344,11 +344,11 @@ static u32 ReadDisaDiffDpfsLvl3(const DisaDiffRWInfo* info, u32 offset, u32 size const u32 offset_lvl3_0 = info->offset_dpfs_lvl3; const u32 offset_lvl3_1 = offset_lvl3_0 + info->size_dpfs_lvl3; const u32 log_lvl3 = info->log_dpfs_lvl3; - + u32 read_start = offset_start; u32 read_end = read_start; u32 bit_state = 0; - + // full reading below while (size && (read_start < offset_end)) { // read bits until bit_state does not match @@ -370,7 +370,7 @@ static u32 ReadDisaDiffDpfsLvl3(const DisaDiffRWInfo* info, u32 offset, u32 size // flip the bit_state bit_state = ~bit_state & 0x1; } - + return size; } @@ -381,11 +381,11 @@ static u32 WriteDisaDiffDpfsLvl3(const DisaDiffRWInfo* info, u32 offset, u32 siz const u32 offset_lvl3_0 = info->offset_dpfs_lvl3; const u32 offset_lvl3_1 = offset_lvl3_0 + info->size_dpfs_lvl3; const u32 log_lvl3 = info->log_dpfs_lvl3; - + u32 write_start = offset_start; u32 write_end = write_start; u32 bit_state = 0; - + // full reading below while (size && (write_start < offset_end)) { // write bits until bit_state does not match @@ -407,40 +407,40 @@ static u32 WriteDisaDiffDpfsLvl3(const DisaDiffRWInfo* info, u32 offset, u32 siz // flip the bit_state bit_state = ~bit_state & 0x1; } - + return size; } - + u32 FixDisaDiffPartitionHash(const DisaDiffRWInfo* info) { const u32 size = info->size_table; u8 sha_buf[0x20]; u8* buf; - + if (!(buf = malloc(size))) return 1; - + if (DisaDiffRead(buf, size, info->offset_table) != FR_OK) { free(buf); return 1; } - + sha_quick(sha_buf, buf, size, SHA256_MODE); - + free(buf); - + if (DisaDiffWrite(sha_buf, 0x20, info->offset_partition_hash) != FR_OK) return 1; - + return 0; } u32 FixDisaDiffIvfcLevel(const DisaDiffRWInfo* info, u32 level, u32 offset, u32 size, u32* next_offset, u32* next_size) { if (level == 0) return FixDisaDiffPartitionHash(info); - + if (level > 4) return 1; - + const u32 offset_ivfc_lvl = (&(info->offset_ivfc_lvl1))[level - 1]; const u32 size_ivfc_lvl = (&(info->size_ivfc_lvl1))[level - 1]; const u32 log_ivfc_lvl = (&(info->log_ivfc_lvl1))[level - 1]; @@ -448,48 +448,48 @@ u32 FixDisaDiffIvfcLevel(const DisaDiffRWInfo* info, u32 level, u32 offset, u32 u32 read_size = block_size; u32 align_offset = (offset >> log_ivfc_lvl) << log_ivfc_lvl; // align starting offset u32 align_size = size + offset - align_offset; // increase size by the amount starting offset decreased when aligned - + if (level != 1) { if (next_offset) *next_offset = (align_offset >> log_ivfc_lvl) * 0x20; if (next_size) *next_size = ((align_size >> log_ivfc_lvl) + (((align_size % block_size) == 0) ? 0 : 1)) * 0x20; } - + u8 sha_buf[0x20]; u8* buf; - + if (!(buf = malloc(block_size))) return 1; - + while (align_size > 0) { if (align_offset + block_size > size_ivfc_lvl) { memset(buf, 0, block_size); read_size -= (align_offset + block_size - size_ivfc_lvl); } - + if (((level == 4) && info->ivfc_use_extlvl4) ? (DisaDiffRead(buf, read_size, align_offset + offset_ivfc_lvl) != FR_OK) : (ReadDisaDiffDpfsLvl3(info, align_offset + offset_ivfc_lvl, read_size, buf) != read_size)) { free(buf); return 1; } - + sha_quick(sha_buf, buf, block_size, SHA256_MODE); - - - if ((level == 1) ? (DisaDiffWrite(sha_buf, 0x20, info->offset_difi + info->offset_master_hash + ((align_offset >> log_ivfc_lvl) * 0x20)) != FR_OK) : + + + if ((level == 1) ? (DisaDiffWrite(sha_buf, 0x20, info->offset_difi + info->offset_master_hash + ((align_offset >> log_ivfc_lvl) * 0x20)) != FR_OK) : (WriteDisaDiffDpfsLvl3(info, (&(info->offset_ivfc_lvl1))[level - 2] + ((align_offset >> log_ivfc_lvl) * 0x20), 0x20, sha_buf) != 0x20)) { free(buf); return 1; } - + align_offset += block_size; align_size = ((align_size < block_size) ? 0 : (align_size - block_size)); } - + free(buf); - + return 0; } - + u32 ReadDisaDiffIvfcLvl4(const char* path, const DisaDiffRWInfo* info, u32 offset, u32 size, void* buffer) { // offset: offset inside IVFC lvl4 // DisaDiffRWInfo not provided? DisaDiffRWInfo info_l; @@ -504,15 +504,15 @@ u32 ReadDisaDiffIvfcLvl4(const char* path, const DisaDiffRWInfo* info, u32 offse return 0; } } - + // open file pointer if (DisaDiffOpen(path) != FR_OK) size = 0; - + // sanity checks - offset & size if (offset > info->size_ivfc_lvl4) return 0; else if (offset + size > info->size_ivfc_lvl4) size = info->size_ivfc_lvl4 - offset; - + if (info->ivfc_use_extlvl4) { if (DisaDiffRead(buffer, size, info->offset_ivfc_lvl4 + offset) != FR_OK) size = 0; @@ -541,22 +541,22 @@ u32 WriteDisaDiffIvfcLvl4(const char* path, const DisaDiffRWInfo* info, u32 offs return 0; } } - + // sanity check - offset & size if (offset + size > info->size_ivfc_lvl4) return 0; - + // open file pointer if (DisaDiffOpen(path) != FR_OK) size = 0; - + if (info->ivfc_use_extlvl4) { if (DisaDiffWrite(buffer, size, info->offset_ivfc_lvl4 + offset) != FR_OK) size = 0; } else { size = WriteDisaDiffDpfsLvl3(info, info->offset_ivfc_lvl4 + offset, size, buffer); } - + if ((size != 0) && ddfp) { // if we're writing to a mounted image, the hash chain will be handled later by vdisadiff u32 hashfix_offset = offset, hashfix_size = size; for (int i = 4; i >= 0; i--) { @@ -566,7 +566,7 @@ u32 WriteDisaDiffIvfcLvl4(const char* path, const DisaDiffRWInfo* info, u32 offs } } } - + DisaDiffClose(); if (cache) free(cache); return size; diff --git a/arm9/source/game/firm.c b/arm9/source/game/firm.c index dfc252e..f9f7509 100644 --- a/arm9/source/game/firm.c +++ b/arm9/source/game/firm.c @@ -169,10 +169,10 @@ u32 SetupSecretKey(u32 keynum) { static u8 __attribute__((aligned(32))) sector[0x200]; static u32 got_keys = 0; u8* key = sector + (keynum*0x10); - + if (keynum >= 0x200/0x10) return 1; // safety - + // try to load full secret sector if (!got_keys) { ReadNandSectors(sector, 0x96, 1, 0x11, NAND_SYSNAND); @@ -185,34 +185,34 @@ u32 SetupSecretKey(u32 keynum) { if (LoadKeyFromFile(key, 0x11, 'N', (keynum == 0) ? "95" : "96") == 0) got_keys |= (0x1<keyX0x15, header->keyX0x15, 1, AES_CNT_ECB_DECRYPT_MODE); if (type) { if (SetupSecretKey((type == 1) ? 0 : 1) != 0) return 1; aes_decrypt(header->keyX0x16, header->keyX0x16, 1, AES_CNT_ECB_DECRYPT_MODE); } - + return 0; } u32 SetupArm9BinaryCrypto(FirmA9LHeader* header) { u32 type = A9L_CRYPTO_TYPE(header); - + if (type == 0) { u8 __attribute__((aligned(32))) keyX0x15[0x10]; memcpy(keyX0x15, header->keyX0x15, 0x10); @@ -230,24 +230,24 @@ u32 SetupArm9BinaryCrypto(FirmA9LHeader* header) { setup_aeskeyY(0x16, header->keyY0x150x16); use_aeskey(0x16); } - + return 0; } u32 DecryptArm9Binary(void* data, u32 offset, u32 size, FirmA9LHeader* a9l) { // offset == offset inside ARM9 binary // ARM9 binary begins 0x800 byte after the ARM9 loader header - + // only process actual ARM9 binary u32 size_bin = GetArm9BinarySize(a9l); if (offset >= size_bin) return 0; else if (size >= size_bin - offset) size = size_bin - offset; - + // decrypt data if (SetupArm9BinaryCrypto(a9l) != 0) return 1; ctr_decrypt_byte(data, data, size, offset, AES_CNT_CTRNAND_MODE, a9l->ctr); - + return 0; } @@ -256,16 +256,16 @@ u32 DecryptFirm(void* data, u32 offset, u32 size, FirmHeader* firm, FirmA9LHeade FirmSectionHeader* arm9s = FindFirmArm9Section(firm); u32 offset_arm9bin = arm9s->offset + ARM9BIN_OFFSET; u32 size_arm9bin = GetArm9BinarySize(a9l); - + // sanity checks if (!size_arm9bin || (size_arm9bin + ARM9BIN_OFFSET > arm9s->size)) return 1; // bad header / data - + // check if ARM9 binary in data if ((offset_arm9bin >= offset + size) || (offset >= offset_arm9bin + size_arm9bin)) return 0; // section not in data - + // determine data / offset / size u8* data8 = (u8*)data; u8* data_i = data8; @@ -277,7 +277,7 @@ u32 DecryptFirm(void* data, u32 offset, u32 size, FirmHeader* firm, FirmA9LHeade size_i = size_arm9bin - offset_i; if (size_i > size - (data_i - data8)) size_i = size - (data_i - data8); - + return DecryptArm9Binary(data_i, offset_i, size_i, a9l); } @@ -290,7 +290,7 @@ u32 DecryptFirmSequential(void* data, u32 offset, u32 size) { static FirmHeader* firmptr = NULL; static FirmA9LHeader* a9lptr = NULL; static FirmSectionHeader* arm9s = NULL; - + // fetch firm header from data if ((offset == 0) && (size >= sizeof(FirmHeader))) { memcpy(&firm, data, sizeof(FirmHeader)); @@ -298,17 +298,17 @@ u32 DecryptFirmSequential(void* data, u32 offset, u32 size) { arm9s = (firmptr) ? FindFirmArm9Section(firmptr) : NULL; a9lptr = NULL; } - + // safety check, firm header pointer if (!firmptr) return 1; - + // fetch ARM9 loader header from data if (arm9s && !a9lptr && (offset <= arm9s->offset) && ((offset + size) >= arm9s->offset + sizeof(FirmA9LHeader))) { memcpy(&a9l, (u8*)data + arm9s->offset - offset, sizeof(FirmA9LHeader)); a9lptr = (ValidateFirmA9LHeader(&a9l) == 0) ? &a9l : NULL; } - + return (a9lptr) ? DecryptFirm(data, offset, size, firmptr, a9lptr) : 0; } @@ -318,17 +318,17 @@ u32 DecryptFirmFull(void* data, u32 size) { FirmSectionHeader* arm9s = FindFirmArm9Section(firm); if (ValidateFirmHeader(firm, size) != 0) return 1; // not a proper firm if (!arm9s) return 0; // no ARM9 section -> not encrypted -> done - + FirmA9LHeader* a9l = (FirmA9LHeader*)(void*) ((u8*) data + arm9s->offset); if (ValidateFirmA9LHeader(a9l) != 0) return 0; // no ARM9bin -> not encrypted -> done - + // decrypt FIRM and ARM9loader header if ((DecryptFirm(data, 0, size, firm, a9l) != 0) || (DecryptA9LHeader(a9l) != 0)) return 1; - + // fix ARM9 section SHA and ARM9 entrypoint sha_quick(arm9s->hash, (u8*) data + arm9s->offset, arm9s->size, SHA256_MODE); firm->entry_arm9 = ARM9ENTRY_FIX(firm); - + return 0; } diff --git a/arm9/source/game/gba.c b/arm9/source/game/gba.c index f967f9e..65a8fb0 100644 --- a/arm9/source/game/gba.c +++ b/arm9/source/game/gba.c @@ -8,20 +8,20 @@ u32 ValidateAgbSaveHeader(AgbSaveHeader* header) { static u8 magic[] = { AGBSAVE_MAGIC }; - + // basic checks if ((memcmp(header->magic, magic, sizeof(magic)) != 0) || (header->unknown0 != 1) || (header->save_start != 0x200) || (header->save_size > AGBSAVE_MAX_SSIZE) || !(GBASAVE_VALID(header->save_size))) return 1; - + // reserved area checks // disabled due to a weird quirk https://github.com/d0k3/GodMode9/issues/412 // for (u32 i = 0; i < sizeof(header->reserved0); i++) if (header->reserved0[i] != 0xFF) return 1; // for (u32 i = 0; i < sizeof(header->reserved1); i++) if (header->reserved1[i] != 0xFF) return 1; // for (u32 i = 0; i < sizeof(header->reserved2); i++) if (header->reserved2[i] != 0xFF) return 1; // for (u32 i = 0; i < sizeof(header->reserved3); i++) if (header->reserved3[i] != 0xFF) return 1; - + // all fine if arriving here return 0; } @@ -30,60 +30,60 @@ u32 ValidateAgbSaveHeader(AgbSaveHeader* header) { u32 ValidateAgbHeader(AgbHeader* agb) { static const u8 logo_sha[0x20] = { AGBLOGO_SHA256 }; u8 logo[0x9C] __attribute__((aligned(4))); - + // check fixed value if (agb->fixed != 0x96) return 1; - + // header checksum u8* hdr = (u8*) agb; u8 checksum = 0x00 - 0x19; for (u32 i = 0xA0; i < 0xBD; i++) checksum -= hdr[i]; if (agb->checksum != checksum) return 1; - + // logo SHA check memcpy(logo, agb->logo, 0x9C); - logo[0x98] &= ~0x84; + logo[0x98] &= ~0x84; logo[0x9A] &= ~0x03; if (sha_cmp(logo_sha, logo, 0x9C, SHA256_MODE) != 0) return 1; - + return 0; } /* u32 ValidateAgbVc(void* data, u32 len) { const u8 magic[] = { GBAVC_MAGIC }; - + if (len < sizeof(AgbHeader) + sizeof(AgbVcFooter)) return 1; - + AgbHeader* header = (AgbHeader*) data; AgbVcFooter* footer = (AgbVcFooter*) (((u8*) data) + len - sizeof(AgbVcFooter)); - + if ((ValidateAgbHeader(header) != 0) || (memcmp(footer->magic, magic, sizeof(magic)) != 0) || (footer->rom_size != len - sizeof(AgbVcFooter))) return 1; - + return 0; } */ // basically reverse ValidateAgbSaveHeader() /* u32 BuildAgbSaveHeader(AgbSaveHeader* header, u64 title_id, u32 save_size) { const u8 magic[] = { AGBSAVE_MAGIC }; - + memset(header, 0x00, sizeof(AgbSaveHeader)); memset(header->reserved0, 0xFF, sizeof(header->reserved0)); memset(header->reserved1, 0xFF, sizeof(header->reserved1)); memset(header->reserved2, 0xFF, sizeof(header->reserved2)); memset(header->reserved3, 0xFF, sizeof(header->reserved3)); - + memcpy(header->magic, magic, sizeof(magic)); header->unknown0 = 0x01; header->title_id = title_id; header->save_start = 0x200; header->save_size = save_size; - + sdmmc_get_cid(0, (u32*) (void*) &(header->sd_cid)); - + return 0; } */ diff --git a/arm9/source/game/gba.h b/arm9/source/game/gba.h index 4ffac20..967b247 100644 --- a/arm9/source/game/gba.h +++ b/arm9/source/game/gba.h @@ -1,7 +1,7 @@ #pragma once #include "common.h" - + #define GBAVC_MAGIC '.', 'C', 'A', 'A' #define AGBSAVE_MAGIC '.', 'S', 'A', 'V' #define AGBSAVE_MAX_SIZE (0x000180 * 0x200) // standard size of the NAND partition @@ -20,14 +20,14 @@ ((tp >= 0x4) && (tp <= 0x9)) ? GBASAVE_FLASH_64K : \ ((tp >= 0xA) && (tp <= 0xD)) ? GBASAVE_FLASH_128K : \ (tp == 0xE) ? GBASAVE_SRAM_32K : 0); // last one means invalid - + #define GBASAVE_VALID(size) \ (((size) == GBASAVE_EEPROM_512) || \ ((size) == GBASAVE_EEPROM_8K) || \ ((size) == GBASAVE_SRAM_32K) || \ ((size) == GBASAVE_FLASH_64K) || \ ((size) == GBASAVE_FLASH_128K)) - + // see: http://problemkaputt.de/gbatek.htm#gbacartridgeheader #define AGB_DESTSTR(code) \ (((code)[3] == 'J') ? "Japan" : \ @@ -36,9 +36,9 @@ ((code)[3] == 'D') ? "German" : \ ((code)[3] == 'F') ? "French" : \ ((code)[3] == 'I') ? "Italian" : \ - ((code)[3] == 'S') ? "Spanish" : "Unknown") + ((code)[3] == 'S') ? "Spanish" : "Unknown") + - // see: http://3dbrew.org/wiki/3DS_Virtual_Console#Footer // still a lot of unknowns in here, also redundant stuff left out typedef struct { @@ -73,7 +73,7 @@ typedef struct { // see: http://problemkaputt.de/gbatek.htm#gbacartridgeheader typedef struct { - u32 arm7_rom_entry; + u32 arm7_rom_entry; u8 logo[0x9C]; char game_title[12]; char game_code[4]; diff --git a/arm9/source/game/ips.c b/arm9/source/game/ips.c index 13cc6c9..76cef60 100644 --- a/arm9/source/game/ips.c +++ b/arm9/source/game/ips.c @@ -113,14 +113,14 @@ int ApplyIPSPatch(const char* patchName, const char* inName, const char* outName int error = IPS_INVALID; UINT outlen_min, outlen_max, outlen_min_mem; snprintf(errName, 256, "%s", patchName); - + if (fvx_open(&patchFile, patchName, FA_READ) != FR_OK) return displayError(IPS_INVALID_FILE_PATH); patchSize = fvx_size(&patchFile); ShowProgress(0, patchSize, patchName); - + patch = malloc(patchSize); if (!patch || fvx_read(&patchFile, patch, patchSize, NULL) != FR_OK) return displayError(IPS_MEMORY); - + // Check validity of patch if (patchSize < 8) return displayError(IPS_INVALID); if (read8() != 'P' || @@ -131,7 +131,7 @@ int ApplyIPSPatch(const char* patchName, const char* inName, const char* outName { return displayError(IPS_INVALID); } - + unsigned int offset = read24(); unsigned int outlen = 0; unsigned int thisout = 0; @@ -144,7 +144,7 @@ int ApplyIPSPatch(const char* patchName, const char* inName, const char* outName ShowProgress(0, patchSize, patchName); ShowProgress(patchOffset, patchSize, patchName); } - + unsigned int size = read16(); if (size == 0) { @@ -180,7 +180,7 @@ int ApplyIPSPatch(const char* patchName, const char* inName, const char* outName outlen_min = outlen; error = IPS_OK; if (w_scrambled) error = IPS_SCRAMBLED; - + // start applying patch bool inPlace = false; if (!CheckWritePermissions(outName)) return displayError(IPS_INVALID_FILE_PATH); @@ -193,19 +193,19 @@ int ApplyIPSPatch(const char* patchName, const char* inName, const char* outName else if ((fvx_open(&inFile, inName, FA_READ) != FR_OK) || (fvx_open(&outFile, outName, FA_CREATE_ALWAYS | FA_WRITE | FA_READ) != FR_OK)) return displayError(IPS_INVALID_FILE_PATH); - + size_t inSize = fvx_size(&inFile); outlen = max(outlen_min, min(inSize, outlen_max)); fvx_lseek(&outFile, max(outlen, outlen_min_mem)); fvx_lseek(&outFile, 0); size_t outSize = outlen; ShowProgress(0, outSize, outName); - + fvx_lseek(&inFile, 0); if (!inPlace && !IPScopy(COPY_IN, min(inSize, outlen), 0)) return displayError(IPS_MEMORY); fvx_lseek(&outFile, inSize); if (outSize > inSize && !IPScopy(COPY_RLE, outSize - inSize, 0)) return displayError(IPS_MEMORY); - + fvx_lseek(&patchFile, 5); offset = read24(); while (offset != 0x454F46) @@ -215,14 +215,14 @@ int ApplyIPSPatch(const char* patchName, const char* inName, const char* outName ShowProgress(0, outSize, outName); ShowProgress(offset, outSize, outName); } - + fvx_lseek(&outFile, offset); unsigned int size = read16(); - if (size == 0 && !IPScopy(COPY_RLE, read16(), read8())) return displayError(IPS_MEMORY); + if (size == 0 && !IPScopy(COPY_RLE, read16(), read8())) return displayError(IPS_MEMORY); else if (size != 0 && !IPScopy(COPY_PATCH, size, 0)) return displayError(IPS_MEMORY); offset = read24(); } - + fvx_lseek(&outFile, outSize); f_truncate(&outFile); return displayError(error); diff --git a/arm9/source/game/ncch.c b/arm9/source/game/ncch.c index 703c37f..9348a4c 100644 --- a/arm9/source/game/ncch.c +++ b/arm9/source/game/ncch.c @@ -11,7 +11,7 @@ u32 ValidateNcchHeader(NcchHeader* header) { if (memcmp(header->magic, "NCCH", 4) != 0) // check magic number return 1; - + u32 ncch_units = (NCCH_EXTHDR_OFFSET + header->size_exthdr) / NCCH_MEDIA_UNIT; // exthdr if (header->size_plain) { // plain region if (header->offset_plain < ncch_units) return 1; // overlapping plain region @@ -26,8 +26,8 @@ u32 ValidateNcchHeader(NcchHeader* header) { ncch_units = (header->offset_romfs + header->size_romfs); } // size check - if (ncch_units > header->size) return 1; - + if (ncch_units > header->size) return 1; + return 0; } @@ -36,7 +36,7 @@ u32 GetNcchCtr(u8* ctr, NcchHeader* ncch, u8 section) { if (ncch->version == 1) { memcpy(ctr, &(ncch->partitionId), 8); if (section == 1) { // ExtHeader ctr - add_ctr(ctr, NCCH_EXTHDR_OFFSET); + add_ctr(ctr, NCCH_EXTHDR_OFFSET); } else if (section == 2) { // ExeFS ctr add_ctr(ctr, ncch->offset_exefs * NCCH_MEDIA_UNIT); } else if (section == 3) { // RomFS ctr @@ -47,7 +47,7 @@ u32 GetNcchCtr(u8* ctr, NcchHeader* ncch, u8 section) { ctr[i] = ((u8*) &(ncch->partitionId))[7-i]; ctr[8] = section; } - + return 0; } @@ -56,25 +56,25 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) { u64 titleId = ncch->programId; u32 hash_seed = ncch->hash_seed; u32 sha256sum[8]; - + memcpy(lseed+16, &(ncch->programId), 8); sha_quick(sha256sum, lseed, 16 + 8, SHA256_MODE); if (hash_seed == sha256sum[0]) { memcpy(seed, lseed, 16); return 0; } - + // setup a large enough buffer u8* buffer = (u8*) malloc(max(STD_BUFFER_SIZE, SEEDSAVE_AREA_SIZE)); if (!buffer) return 1; - + // try to grab the seed from NAND database const char* nand_drv[] = {"1:", "4:"}; // SysNAND and EmuNAND for (u32 i = 0; i < countof(nand_drv); i++) { UINT btr = 0; FIL file; char path[128]; - + // grab the key Y from movable.sed u8 movable_keyy[16]; snprintf(path, 128, "%s/private/movable.sed", nand_drv[i]); @@ -83,17 +83,17 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) { f_lseek(&file, 0x110); f_read(&file, movable_keyy, 0x10, &btr); f_close(&file); - + // build the seed save path sha_quick(sha256sum, movable_keyy, 0x10, SHA256_MODE); snprintf(path, 128, "%s/data/%08lX%08lX%08lX%08lX/sysdata/0001000F/00000000", nand_drv[i], sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); - + // check seedsave for seed u8* seeddb = buffer; if (ReadDisaDiffIvfcLvl4(path, NULL, SEEDSAVE_AREA_OFFSET, SEEDSAVE_AREA_SIZE, seeddb) != SEEDSAVE_AREA_SIZE) continue; - + // search for the seed for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { if (titleId != getle64(seeddb + (s*8))) continue; @@ -106,10 +106,10 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) { } } } - + // not found -> try seeddb.bin SeedInfo* seeddb = (SeedInfo*) (void*) buffer; - size_t len = LoadSupportFile(SEEDDB_NAME, seeddb, STD_BUFFER_SIZE); + size_t len = LoadSupportFile(SEEDDB_NAME, seeddb, STD_BUFFER_SIZE); if (len && (seeddb->n_entries <= (len - 16) / 32)) { // check filesize / seeddb size for (u32 s = 0; s < seeddb->n_entries; s++) { if (titleId != seeddb->entries[s].titleId) @@ -123,7 +123,7 @@ u32 GetNcchSeed(u8* seed, NcchHeader* ncch) { } } } - + // out of options -> failed! free(buffer); return 1; @@ -150,10 +150,10 @@ u32 SetNcchKey(NcchHeader* ncch, u16 crypto, u32 keyid) { u8 flags7 = crypto & 0xFF; u32 keyslot = (!keyid || !flags3) ? 0x2C : // standard / secure3 / secure4 / 7.x crypto (flags3 == 0x0A) ? 0x18 : (flags3 == 0x0B) ? 0x1B : 0x25; - + if (flags7 & 0x04) return 1; - + if (flags7 & 0x01) { // fixed key crypto // from https://github.com/profi200/Project_CTR/blob/master/makerom/pki/dev.h u8 zeroKey[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -164,11 +164,11 @@ u32 SetNcchKey(NcchHeader* ncch, u16 crypto, u32 keyid) { use_aeskey(0x11); return 0; } - + // load key X from file if required if ((keyslot != 0x2C) && (LoadKeyFromFile(NULL, keyslot, 'X', NULL) != 0)) return 1; - + // key Y for seed and non seed if (keyid && (flags7 & 0x20)) { // seed crypto static u8 seedkeyY[16+16] __attribute__((aligned(32))) = { 0 }; @@ -188,12 +188,12 @@ u32 SetNcchKey(NcchHeader* ncch, u16 crypto, u32 keyid) { setup_aeskeyY(keyslot, ncch->signature); } use_aeskey(keyslot); - + return 0; } // this is used to force and check crypto setup -// (also prevents SHA register usage later on) +// (also prevents SHA register usage later on) u32 SetupNcchCrypto(NcchHeader* ncch, u16 crypt_to) { u16 crypt_from = NCCH_GET_CRYPTO(ncch); u32 res_from = ((crypt_from & NCCH_NOCRYPTO) || @@ -207,14 +207,14 @@ u32 CryptNcchSection(void* data, u32 offset_data, u32 size_data, u32 offset_sect u32 offset_ctr, NcchHeader* ncch, u32 snum, u16 crypt_to, u32 keyid) { u16 crypt_from = NCCH_GET_CRYPTO(ncch); const u32 mode = AES_CNT_CTRNAND_MODE; - + // check if section in data if ((offset_section >= offset_data + size_data) || (offset_data >= offset_section + size_section) || !size_section) { return 0; // section not in data } - + // determine data / offset / size u8* data8 = (u8*)data; u8* data_i = data8; @@ -226,7 +226,7 @@ u32 CryptNcchSection(void* data, u32 offset_data, u32 size_data, u32 offset_sect size_i = size_section - offset_i; if (size_i > size_data - (data_i - data8)) size_i = size_data - (data_i - data8); - + // actual decryption stuff u8 ctr[16]; GetNcchCtr(ctr, ncch, snum); @@ -238,7 +238,7 @@ u32 CryptNcchSection(void* data, u32 offset_data, u32 size_data, u32 offset_sect if (SetNcchKey(ncch, crypt_to, keyid) != 0) return 1; ctr_decrypt_byte(data_i, data_i, size_i, offset_i + offset_ctr, mode, ctr); } - + return 0; } @@ -247,11 +247,11 @@ u32 CryptNcch(void* data, u32 offset, u32 size, NcchHeader* ncch, ExeFsHeader* e const u32 offset_flag3 = 0x188 + 3; const u32 offset_flag7 = 0x188 + 7; u16 crypt_from = NCCH_GET_CRYPTO(ncch); - + // check for encryption if ((crypt_to & crypt_from & NCCH_NOCRYPTO) || (crypt_to == crypt_from)) return 0; // desired end result already met - + // ncch flags handling if ((offset <= offset_flag3) && (offset + size > offset_flag3)) ((u8*)data)[offset_flag3 - offset] = (crypt_to >> 8); @@ -259,7 +259,7 @@ u32 CryptNcch(void* data, u32 offset, u32 size, NcchHeader* ncch, ExeFsHeader* e ((u8*)data)[offset_flag7 - offset] &= ~(0x01|0x20|0x04); ((u8*)data)[offset_flag7 - offset] |= (crypt_to & (0x01|0x20|0x04)); } - + // exthdr handling if (ncch->size_exthdr) { if (CryptNcchSection(data, offset, size, @@ -267,14 +267,14 @@ u32 CryptNcch(void* data, u32 offset, u32 size, NcchHeader* ncch, ExeFsHeader* e NCCH_EXTHDR_SIZE, 0, ncch, 1, crypt_to, 0) != 0) return 1; } - + // exefs handling if (ncch->size_exefs) { // exefs header handling if (CryptNcchSection(data, offset, size, ncch->offset_exefs * NCCH_MEDIA_UNIT, 0x200, 0, ncch, 2, crypt_to, 0) != 0) return 1; - + // exefs file handling if (exefs) for (u32 i = 0; i < 10; i++) { ExeFsFileHeader* file = exefs->files + i; @@ -291,7 +291,7 @@ u32 CryptNcch(void* data, u32 offset, u32 size, NcchHeader* ncch, ExeFsHeader* e ncch, 2, crypt_to, 0) != 0) return 1; } } - + // romfs handling if (ncch->size_romfs) { if (CryptNcchSection(data, offset, size, @@ -299,7 +299,7 @@ u32 CryptNcch(void* data, u32 offset, u32 size, NcchHeader* ncch, ExeFsHeader* e ncch->size_romfs * NCCH_MEDIA_UNIT, 0, ncch, 3, crypt_to, 1) != 0) return 1; } - + return 0; } @@ -311,31 +311,31 @@ u32 CryptNcchSequential(void* data, u32 offset, u32 size, u16 crypt_to) { static ExeFsHeader exefs = { 0 }; static NcchHeader* ncchptr = NULL; static ExeFsHeader* exefsptr = NULL; - + // fetch ncch header from data if ((offset == 0) && (size >= sizeof(NcchHeader))) { memcpy(&ncch, data, sizeof(NcchHeader)); ncchptr = (ValidateNcchHeader(&ncch) == 0) ? &ncch : NULL; exefsptr = NULL; } - + // safety check, ncch pointer if (!ncchptr) return 1; - + // fetch exefs header from data if (ncchptr->offset_exefs && !exefsptr) { u32 offset_exefs = ncchptr->offset_exefs * NCCH_MEDIA_UNIT; if ((offset <= offset_exefs) && ((offset + size) >= offset_exefs + sizeof(ExeFsHeader))) { memcpy(&exefs, (u8*)data + offset_exefs - offset, sizeof(ExeFsHeader)); - if ((NCCH_ENCRYPTED(ncchptr)) && + if ((NCCH_ENCRYPTED(ncchptr)) && (DecryptNcch((u8*) &exefs, offset_exefs, sizeof(ExeFsHeader), ncchptr, NULL) != 0)) return 1; if (ValidateExeFsHeader(&exefs, 0) != 0) return 1; exefsptr = &exefs; } } - + return CryptNcch(data, offset, size, ncchptr, exefsptr, crypt_to); } @@ -343,17 +343,17 @@ u32 SetNcchSdFlag(void* data) { // data must be at least 0x600 byte and start wi NcchHeader* ncch = (NcchHeader*) data; NcchExtHeader* exthdr = (NcchExtHeader*) (void*) ((u8*)data + NCCH_EXTHDR_OFFSET); NcchExtHeader exthdr_dec; - + if ((ValidateNcchHeader(ncch) != 0) || (!ncch->size_exthdr)) return 0; // no extheader memcpy(&exthdr_dec, exthdr, sizeof(NcchExtHeader)); if (DecryptNcch((u8*) &exthdr_dec, NCCH_EXTHDR_OFFSET, sizeof(NcchExtHeader), ncch, NULL) != 0) return 1; if (exthdr_dec.flag & (1<<1)) return 0; // flag already set - + exthdr_dec.flag |= (1<<1); exthdr->flag ^= (1<<1); sha_quick(ncch->hash_exthdr, &exthdr_dec, 0x400, SHA256_MODE); - + return 0; } diff --git a/arm9/source/game/ncchinfo.c b/arm9/source/game/ncchinfo.c index 6381836..e148652 100644 --- a/arm9/source/game/ncchinfo.c +++ b/arm9/source/game/ncchinfo.c @@ -18,25 +18,25 @@ u32 FixNcchInfoEntry(NcchInfoEntry* entry, u32 version) { } else if (version != 4) { // !ncchinfo v4.0/v4.1/v4.2 return 1; } - + // poor man's UTF-16 -> UTF-8 if (entry->filename[1] == 0x00) { for (u32 i = 1; i < (sizeof(entry->filename) / 2); i++) entry->filename[i] = entry->filename[i*2]; } - + // fix sdmc: prefix if (memcmp(entry->filename, "sdmc:", 5) == 0) memmove(entry->filename, entry->filename + 5, 112 - 5); - + // workaround (1) for older (v4.0) ncchinfo.bin // this combination means seed crypto rather than FixedKey if ((entry->ncchFlag7 == 0x01) && entry->ncchFlag3) entry->ncchFlag7 = 0x20; - + // workaround (2) for older (v4.1) ncchinfo.bin if (!entry->size_b) entry->size_b = entry->size_mb * 1024 * 1024; - + return 0; } @@ -50,10 +50,10 @@ u32 BuildNcchInfoXorpad(void* buffer, NcchInfoEntry* entry, u32 size, u32 offset ncch.programId = ncch.partitionId = entry->titleId; if (SetNcchKey(&ncch, NCCH_GET_CRYPTO(&ncch), 1) != 0) return 1; - + // write xorpad memset(buffer, 0, size); ctr_decrypt_byte(buffer, buffer, size, offset, AES_CNT_CTRNAND_MODE, entry->ctr); - + return 0; } diff --git a/arm9/source/game/ncsd.c b/arm9/source/game/ncsd.c index 3fb5213..77a410e 100644 --- a/arm9/source/game/ncsd.c +++ b/arm9/source/game/ncsd.c @@ -6,7 +6,7 @@ u32 ValidateNcsdHeader(NcsdHeader* header) { if ((memcmp(header->magic, "NCSD", 4) != 0) || // check magic number (memcmp(header->partitions_fs_type, zeroes, 8) != 0) || !header->mediaId) // prevent detection of NAND images return 1; - + u32 data_units = 0; for (u32 i = 0; i < 8; i++) { NcchPartition* partition = header->partitions + i; @@ -18,7 +18,7 @@ u32 ValidateNcsdHeader(NcsdHeader* header) { } if (data_units > header->size) return 1; - + return 0; } @@ -30,7 +30,7 @@ u64 GetNcsdTrimmedSize(NcsdHeader* header) { if (!partition->size) continue; data_units = (partition_end > data_units) ? partition_end : data_units; } - + return data_units * NCSD_MEDIA_UNIT; } @@ -38,11 +38,11 @@ u64 GetNcsdTrimmedSize(NcsdHeader* header) { u32 CryptNcsdSequential(void* data, u32 offset_data, u32 size_data, u16 crypto) { // warning: this will only work for sequential processing static NcsdHeader ncsd; - + // fetch ncsd header from data if ((offset_data == 0) && (size_data >= sizeof(NcsdHeader))) memcpy(&ncsd, data, sizeof(NcsdHeader)); - + for (u32 i = 0; i < 8; i++) { NcchPartition* partition = ncsd.partitions + i; u32 offset_p = partition->offset * NCSD_MEDIA_UNIT; @@ -68,7 +68,7 @@ u32 CryptNcsdSequential(void* data, u32 offset_data, u32 size_data, u16 crypto) if (CryptNcchSequential(data_i, offset_i, size_i, crypto) != 0) return 1; } - + return 0; } diff --git a/arm9/source/game/nds.c b/arm9/source/game/nds.c index a6f3448..04d45a5 100644 --- a/arm9/source/game/nds.c +++ b/arm9/source/game/nds.c @@ -32,7 +32,7 @@ u32 BuildTwlSaveHeader(void* sav, u32 size) { if (size / (u32) sct_size > 0xFFFF) return 1; - // fit max number of sectors into size + // fit max number of sectors into size // that's how Nintendo does it ¯\_(ツ)_/¯ const u16 n_sct_max = size / sct_size; u16 n_sct = 1; @@ -143,15 +143,15 @@ u32 FindNitroRomDir(u32 dirid, u32* fileid, u8** fnt_entry, TwlHeader* hdr, u8* NitroFntBaseEntry* fnt_base = (NitroFntBaseEntry*) fnt; NitroFntBaseEntry* fnt_dir = &((NitroFntBaseEntry*) fnt)[dirid]; NitroFatEntry* fat_lut = (NitroFatEntry*) fat; - + // base sanity checks if (fnt_base->parent_id*sizeof(NitroFntBaseEntry) > fnt_base->subtable_offset) return 1; // invalid FNT if (dirid >= fnt_base->parent_id) return 1; // dir ID out of bounds - + // set first FNT entry / fileid *fnt_entry = fnt + fnt_dir->subtable_offset; *fileid = fnt_dir->file0_id; - + // check subtable / directory validity u32 fid = *fileid; for (u8* entry = *fnt_entry;; entry = FNT_ENTRY_NEXT(entry)) { @@ -161,29 +161,29 @@ u32 FindNitroRomDir(u32 dirid, u32* fileid, u8** fnt_entry, TwlHeader* hdr, u8* if (!FNT_ENTRY_ISDIR(entry)) fid++; } if (fid*sizeof(NitroFatEntry) > hdr->fat_size) return 1; // corrupt fnt / fat - - + + return 0; } u32 NextNitroRomEntry(u32* fileid, u8** fnt_entry) { // check for end of subtable if (!*fnt_entry || !**fnt_entry) return 1; - + // advance to next entry if (!FNT_ENTRY_ISDIR(*fnt_entry)) (*fileid)++; *fnt_entry += FNT_ENTRY_LEN(*fnt_entry); - + // check for end of subtable if (!**fnt_entry) return 1; - + return 0; } u32 ReadNitroRomEntry(u64* offset, u64* size, bool* is_dir, u32 fileid, u8* fnt_entry, u8* fat) { // check for end of subtable if (!fnt_entry || !*fnt_entry) return 1; - + // decipher FNT entry *is_dir = FNT_ENTRY_ISDIR(fnt_entry); if (!(*is_dir)) { // for files @@ -195,6 +195,6 @@ u32 ReadNitroRomEntry(u64* offset, u64* size, bool* is_dir, u32 fileid, u8* fnt_ *offset = (u64) (fnt_entry[1+fnlen]|(fnt_entry[1+fnlen+1]<<8)) & 0xFFF; // dir ID goes in offset *size = 0; } - + return 0; } diff --git a/arm9/source/game/nds.h b/arm9/source/game/nds.h index 0931f00..03de7ef 100644 --- a/arm9/source/game/nds.h +++ b/arm9/source/game/nds.h @@ -7,7 +7,7 @@ // see: http://problemkaputt.de/gbatek.htm#dscartridgeicontitle // v0x0001 -> 0x0840 byte (contains JPN, USA, FRE, GER, ITA, ESP titles) // v0x0002 -> 0x0940 byte (adds CHN title) -// v0x0003 -> 0x0A40 byte (adds KOR title) +// v0x0003 -> 0x0A40 byte (adds KOR title) // v0x0103 -> 0x23C0 byte (adds TWL animated icon data) #define TWLICON_SIZE_DATA(v) ((v == 0x0001) ? 0x0840 : (v == 0x0002) ? 0x0940 : \ (v == 0x0003) ? 0x1240 : (v == 0x0103) ? 0x23C0 : 0x0000) diff --git a/arm9/source/game/romfs.c b/arm9/source/game/romfs.c index 4273e22..28badcc 100644 --- a/arm9/source/game/romfs.c +++ b/arm9/source/game/romfs.c @@ -58,12 +58,12 @@ u32 BuildLv3Index(RomFsLv3Index* index, u8* lv3) { index->filehash = (u32*) (void*) (lv3 + hdr->offset_filehash); index->filemeta = lv3 + hdr->offset_filemeta; index->filedata = NULL; - + index->mod_dir = (hdr->size_dirhash / sizeof(u32)); index->mod_file = (hdr->size_filehash / sizeof(u32)); index->size_dirmeta = hdr->size_dirmeta; index->size_filemeta = hdr->size_filemeta; - + return 0; } @@ -77,13 +77,13 @@ u32 HashLv3Path(u16* wname, u32 name_len, u32 offset_parent) { RomFsLv3DirMeta* GetLv3DirMeta(const char* name, u32 offset_parent, RomFsLv3Index* index) { RomFsLv3DirMeta* meta; - + // wide (UTF-16) name u16 wname[256]; int name_len = utf8_to_utf16(wname, (u8*) name, 255, 255); if (name_len <= 0) return NULL; wname[name_len] = 0; - + // hashing, first offset u32 hash = HashLv3Path(wname, name_len, offset_parent); u32 offset = index->dirhash[hash % index->mod_dir]; @@ -96,19 +96,19 @@ RomFsLv3DirMeta* GetLv3DirMeta(const char* name, u32 offset_parent, RomFsLv3Inde (memcmp(wname, meta->wname, name_len * 2) == 0)) break; } - - return (offset >= index->size_dirmeta) ? NULL : meta; + + return (offset >= index->size_dirmeta) ? NULL : meta; } RomFsLv3FileMeta* GetLv3FileMeta(const char* name, u32 offset_parent, RomFsLv3Index* index) { RomFsLv3FileMeta* meta; - + // wide (UTF-16) name u16 wname[256]; int name_len = utf8_to_utf16(wname, (u8*) name, 255, 255); if (name_len <= 0) return NULL; wname[name_len] = 0; - + // hashing, first offset u32 hash = HashLv3Path(wname, name_len, offset_parent); u32 offset = index->filehash[hash % index->mod_file]; @@ -121,6 +121,6 @@ RomFsLv3FileMeta* GetLv3FileMeta(const char* name, u32 offset_parent, RomFsLv3In (memcmp(wname, meta->wname, name_len * 2) == 0)) break; } - - return (offset >= index->size_filemeta) ? NULL : meta; + + return (offset >= index->size_filemeta) ? NULL : meta; } diff --git a/arm9/source/game/tad.c b/arm9/source/game/tad.c index 927b345..91c5d5e 100644 --- a/arm9/source/game/tad.c +++ b/arm9/source/game/tad.c @@ -4,14 +4,14 @@ u32 BuildTadContentTable(void* table, void* header) { TadHeader* hdr = (TadHeader*) header; TadContentTable* tbl = (TadContentTable*) table; - + if (strncmp(hdr->magic, TAD_HEADER_MAGIC, strlen(TAD_HEADER_MAGIC)) != 0) return 1; - + tbl->banner_end = 0 + sizeof(TadBanner) + sizeof(TadBlockMetaData); tbl->header_end = tbl->banner_end + sizeof(TadHeader) + sizeof(TadBlockMetaData); tbl->footer_end = tbl->header_end + sizeof(TadFooter) + sizeof(TadBlockMetaData); - + u32 content_end_last = tbl->footer_end; for (u32 i = 0; i < TAD_NUM_CONTENT; i++) { tbl->content_end[i] = content_end_last; @@ -19,6 +19,6 @@ u32 BuildTadContentTable(void* table, void* header) { tbl->content_end[i] += align(hdr->content_size[i], 0x10) + sizeof(TadBlockMetaData); content_end_last = tbl->content_end[i]; } - + return 0; } diff --git a/arm9/source/game/ticket.c b/arm9/source/game/ticket.c index bc617e4..c388192 100644 --- a/arm9/source/game/ticket.c +++ b/arm9/source/game/ticket.c @@ -23,18 +23,18 @@ u32 ValidateTicketSignature(Ticket* ticket) { static bool got_modexp = false; static u32 mod[0x100 / 0x4] = { 0 }; static u32 exp = 0; - + if (!got_modexp) { // grab mod/exp from cert from cert.db if (LoadCertFromCertDb(0x3F10, NULL, mod, &exp) == 0) got_modexp = true; else return 1; } - + if (!RSA_setKey2048(3, mod, exp) || !RSA_verify2048((void*) &(ticket->signature), (void*) &(ticket->issuer), GetTicketSize(ticket) - 0x140)) return 1; - + return 0; } @@ -59,7 +59,7 @@ u32 BuildFakeTicket(Ticket* ticket, u8* title_id) { ticket->audit = 0x01; // whatever memcpy(ticket->content_index, ticket_cnt_index, sizeof(ticket_cnt_index)); memset(&ticket->content_index[sizeof(ticket_cnt_index)], 0xFF, 0x80); // 1024 content indexes - + return 0; } @@ -73,14 +73,14 @@ u32 GetTicketSize(const Ticket* ticket) { u32 BuildTicketCert(u8* tickcert) { static const u8 cert_hash_expected[0x20] = { - 0xDC, 0x15, 0x3C, 0x2B, 0x8A, 0x0A, 0xC8, 0x74, 0xA9, 0xDC, 0x78, 0x61, 0x0E, 0x6A, 0x8F, 0xE3, + 0xDC, 0x15, 0x3C, 0x2B, 0x8A, 0x0A, 0xC8, 0x74, 0xA9, 0xDC, 0x78, 0x61, 0x0E, 0x6A, 0x8F, 0xE3, 0xE6, 0xB1, 0x34, 0xD5, 0x52, 0x88, 0x73, 0xC9, 0x61, 0xFB, 0xC7, 0x95, 0xCB, 0x47, 0xE6, 0x97 }; static const u8 cert_hash_expected_dev[0x20] = { 0x97, 0x2A, 0x32, 0xFF, 0x9D, 0x4B, 0xAA, 0x2F, 0x1A, 0x24, 0xCF, 0x21, 0x13, 0x87, 0xF5, 0x38, 0xC6, 0x4B, 0xD4, 0x8F, 0xDF, 0x13, 0x21, 0x3D, 0xFC, 0x72, 0xFC, 0x8D, 0x9F, 0xDD, 0x01, 0x0E }; - + // open certs.db file on SysNAND FIL db; UINT bytes_read; @@ -94,13 +94,13 @@ u32 BuildTicketCert(u8* tickcert) { f_lseek(&db, 0x3A00); f_read(&db, tickcert + 0x4F0, 0x210, &bytes_read); f_close(&db); - + // check the certificate hash u8 cert_hash[0x20]; sha_quick(cert_hash, tickcert, TICKET_CDNCERT_SIZE, SHA256_MODE); if (memcmp(cert_hash, IS_DEVKIT ? cert_hash_expected_dev : cert_hash_expected, 0x20) != 0) return 1; - + return 0; } diff --git a/arm9/source/game/ticketdb.c b/arm9/source/game/ticketdb.c index f1a1f86..8160652 100644 --- a/arm9/source/game/ticketdb.c +++ b/arm9/source/game/ticketdb.c @@ -32,10 +32,10 @@ u32 CryptTitleKey(TitleKeyEntry* tik, bool encrypt, bool devkit) { {0x75, 0x05, 0x52, 0xBF, 0xAA, 0x1C, 0x04, 0x07, 0x55, 0xC8, 0xD5, 0x9A, 0x55, 0xF9, 0xAD, 0x1F} , // 4 {0xAA, 0xDA, 0x4C, 0xA8, 0xF6, 0xE5, 0xA9, 0x77, 0xE0, 0xA0, 0xF9, 0xE4, 0x76, 0xCF, 0x0D, 0x63} , // 5 }; - + u32 mode = (encrypt) ? AES_CNT_TITLEKEY_ENCRYPT_MODE : AES_CNT_TITLEKEY_DECRYPT_MODE; u8 ctr[16] = { 0 }; - + // setup key 0x3D // ctr if (tik->commonkey_idx >= 6) return 1; if (!devkit) setup_aeskeyY(0x3D, (void*) common_keyy[tik->commonkey_idx]); @@ -43,7 +43,7 @@ u32 CryptTitleKey(TitleKeyEntry* tik, bool encrypt, bool devkit) { use_aeskey(0x3D); memcpy(ctr, tik->title_id, 8); set_ctr(ctr); - + // decrypt / encrypt the titlekey aes_decrypt(tik->titlekey, tik->titlekey, 1, mode); return 0; @@ -54,7 +54,7 @@ u32 GetTitleKey(u8* titlekey, Ticket* ticket) { memcpy(tik.title_id, ticket->title_id, 8); memcpy(tik.titlekey, ticket->titlekey, 16); tik.commonkey_idx = ticket->commonkey_idx; - + if (CryptTitleKey(&tik, false, TICKET_DEVKIT(ticket)) != 0) return 1; memcpy(titlekey, tik.titlekey, 16); return 0; @@ -64,7 +64,7 @@ u32 FindTicket(Ticket** ticket, u8* title_id, bool force_legit, bool emunand) { const char* path_db = TICKDB_PATH(emunand); // EmuNAND / SysNAND char path_store[256] = { 0 }; char* path_bak = NULL; - + strncpy(path_store, GetMountPath(), 256); if (*path_store) path_bak = path_store; if (!InitImgFS(path_db)) @@ -81,37 +81,37 @@ u32 FindTicket(Ticket** ticket, u8* title_id, bool force_legit, bool emunand) { for (u32 i = force_legit ? 1 : 0; i < 4; i++) { snprintf(dir_path, 12, "T:/%s", virtual_tickdb_dirs[i]); - + if (fvx_opendir(&dir, dir_path) != FR_OK) { InitImgFS(path_bak); return 1; } - + while ((fvx_readdir(&dir, &fno) == FR_OK) && *(fno.fname)) { if (strncmp(tid_string, fno.fname, 16) == 0) { snprintf(tik_path, 64, "%s/%s", dir_path, fno.fname); - + u32 size = fvx_qsize(tik_path); if (!(*ticket = malloc(size))) { InitImgFS(path_bak); return 1; } - + if ((fvx_qread(tik_path, *ticket, 0, size, NULL) != FR_OK) || (force_legit && (ValidateTicketSignature(*ticket) != 0))) { free(*ticket); InitImgFS(path_bak); return 1; } - + InitImgFS(path_bak); return 0; } } - + fvx_closedir(&dir); } - + InitImgFS(path_bak); return 1; } @@ -120,12 +120,12 @@ u32 FindTitleKey(Ticket* ticket, u8* title_id) { bool found = false; TitleKeysInfo* tikdb = (TitleKeysInfo*) malloc(STD_BUFFER_SIZE); // more than enough if (!tikdb) return 1; - + // search for a titlekey inside encTitleKeys.bin / decTitleKeys.bin // when found, add it to the ticket for (u32 enc = 0; (enc <= 1) && !found; enc++) { u32 len = LoadSupportFile((enc) ? TIKDB_NAME_ENC : TIKDB_NAME_DEC, tikdb, STD_BUFFER_SIZE); - + if (len == 0) continue; // file not found if (tikdb->n_entries > (len - 16) / 32) continue; // filesize / titlekey db size mismatch @@ -141,7 +141,7 @@ u32 FindTitleKey(Ticket* ticket, u8* title_id) { break; } } - + free(tikdb); return (found) ? 0 : 1; } diff --git a/arm9/source/game/tie.c b/arm9/source/game/tie.c index f081db9..465d660 100644 --- a/arm9/source/game/tie.c +++ b/arm9/source/game/tie.c @@ -8,7 +8,7 @@ u32 BuildTitleInfoEntryTmd(TitleInfoEntry* tie, TitleMetaData* tmd, bool sd) { u64 title_id = getbe64(tmd->title_id); bool has_idx1 = false; bool has_idx2 = false; - + // set basic values memset(tie, 0x00, sizeof(TitleInfoEntry)); tie->title_type = 0x40; @@ -34,7 +34,7 @@ u32 BuildTitleInfoEntryTmd(TitleInfoEntry* tie, TitleMetaData* tmd, bool sd) { ((tmd->twl_flag & 0x2) ? align(sizeof(TwlIconData), align_size) : 0); } - // contents title size + some additional stuff + // contents title size + some additional stuff TmdContentChunk* chunk = (TmdContentChunk*) (tmd + 1); tie->content0_id = getbe32(chunk->id); for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++, chunk++) { @@ -55,7 +55,7 @@ u32 BuildTitleInfoEntryTmd(TitleInfoEntry* tie, TitleMetaData* tmd, bool sd) { u32 BuildTitleInfoEntryTwl(TitleInfoEntry* tie, TitleMetaData* tmd, TwlHeader* twl) { u64 title_id = getbe64(tmd->title_id); - + // build the basic titledb entry if (BuildTitleInfoEntryTmd(tie, tmd, false) != 0) return 1; @@ -90,7 +90,7 @@ u32 BuildTitleInfoEntryNcch(TitleInfoEntry* tie, TitleMetaData* tmd, NcchHeader* // NCCH titles need no content0 ID tie->content0_id = 0; - + // specific flags // see: http://3dbrew.org/wiki/Titles if (!((title_id >> 32) & 0x10)) // not a system title diff --git a/arm9/source/game/tmd.c b/arm9/source/game/tmd.c index 93e8d0f..25c7c47 100644 --- a/arm9/source/game/tmd.c +++ b/arm9/source/game/tmd.c @@ -18,18 +18,18 @@ u32 ValidateTmdSignature(TitleMetaData* tmd) { static bool got_modexp = false; static u32 mod[0x100 / 4] = { 0 }; static u32 exp = 0; - + if (!got_modexp) { // grab mod/exp from cert from cert.db if (LoadCertFromCertDb(0x3C10, NULL, mod, &exp) == 0) got_modexp = true; else return 1; } - + if (!RSA_setKey2048(3, mod, exp) || !RSA_verify2048((void*) &(tmd->signature), (void*) &(tmd->issuer), 0xC4)) return 1; - + return 0; } @@ -98,20 +98,20 @@ u32 BuildFakeTmd(TitleMetaData* tmd, u8* title_id, u32 n_contents, u32 save_size memcpy(tmd->contentinfo[0].cmd_count, tmd->content_count, 2); memset(tmd->contentinfo[0].hash, 0xFF, 0x20); // placeholder (hash) // nothing to do for content list (yet) - + return 0; } u32 BuildTmdCert(u8* tmdcert) { static const u8 cert_hash_expected[0x20] = { - 0x91, 0x5F, 0x77, 0x3A, 0x07, 0x82, 0xD4, 0x27, 0xC4, 0xCE, 0xF5, 0x49, 0x25, 0x33, 0xE8, 0xEC, + 0x91, 0x5F, 0x77, 0x3A, 0x07, 0x82, 0xD4, 0x27, 0xC4, 0xCE, 0xF5, 0x49, 0x25, 0x33, 0xE8, 0xEC, 0xF6, 0xFE, 0xA1, 0xEB, 0x8C, 0xCF, 0x59, 0x6E, 0x69, 0xBA, 0x2A, 0x38, 0x8D, 0x73, 0x8A, 0xE1 }; static const u8 cert_hash_expected_dev[0x20] = { 0x49, 0xC9, 0x41, 0x56, 0xCA, 0x86, 0xBD, 0x1F, 0x36, 0x51, 0x51, 0x6A, 0x4A, 0x9F, 0x54, 0xA1, 0xC2, 0xE9, 0xCA, 0x93, 0x94, 0xF4, 0x29, 0xA0, 0x38, 0x54, 0x75, 0xFF, 0xAB, 0x6E, 0x8E, 0x71 }; - + // open certs.db file on SysNAND FIL db; UINT bytes_read; @@ -125,12 +125,12 @@ u32 BuildTmdCert(u8* tmdcert) { f_lseek(&db, 0x3A00); f_read(&db, tmdcert + 0x4F0, 0x210, &bytes_read); f_close(&db); - + // check the certificate hash u8 cert_hash[0x20]; sha_quick(cert_hash, tmdcert, TMD_CDNCERT_SIZE, SHA256_MODE); if (memcmp(cert_hash, IS_DEVKIT ? cert_hash_expected_dev : cert_hash_expected, 0x20) != 0) return 1; - + return 0; } diff --git a/arm9/source/gamecart/card_spi.c b/arm9/source/gamecart/card_spi.c index c4e85d7..914771e 100644 --- a/arm9/source/gamecart/card_spi.c +++ b/arm9/source/gamecart/card_spi.c @@ -30,7 +30,7 @@ #define SPI_512B_EEPROM_CMD_RDLO 3 #define SPI_512B_EEPROM_CMD_RDHI 11 -#define SPI_EEPROM_CMD_WRITE 2 +#define SPI_EEPROM_CMD_WRITE 2 #define SPI_CMD_READ 3 @@ -119,7 +119,7 @@ int CardSPIWriteRead(CardSPIType type, const void* cmd, u32 cmdSize, void* answe SPI_DoXfer(SPI_DEV_CART_FLASH, transfers, 3, true); REG_CFG9_CARDCTL &= ~CARDCTL_SPICARD; - + return 0; } @@ -148,12 +148,12 @@ int CardSPIEnableWriting_regular(CardSPIType type) { if (res) return res; cmd = SPI_CMD_RDSR; - + do { res = CardSPIWriteRead(type, &cmd, 1, &statusReg, 1, 0, 0); if (res) return res; } while(statusReg & ~SPI_FLG_WEL); - + return 0; } @@ -176,17 +176,17 @@ int CardSPIReadJEDECIDAndStatusReg(CardSPIType type, u32* id, u8* statusReg) { u32 id_ = 0; int res = CardSPIWaitWriteEnd(type, 0); if (res) return res; - + if ((res = CardSPIWriteRead(type, &cmd, 1, idbuf, 3, 0, 0))) return res; - + id_ = (idbuf[0] << 16) | (idbuf[1] << 8) | idbuf[2]; cmd = SPI_CMD_RDSR; - + if ((res = CardSPIWriteRead(type, &cmd, 1, ®, 1, 0, 0))) return res; - + if (id) *id = id_; if (statusReg) *statusReg = reg; - + return 0; } @@ -207,19 +207,19 @@ u32 CardSPIGetCapacity(CardSPIType type) { int CardSPIWriteSaveData_9bit(CardSPIType type, u32 offset, const void* data, u32 size) { u8 cmd[2] = { (offset >= 0x100) ? SPI_512B_EEPROM_CMD_WRHI : SPI_512B_EEPROM_CMD_WRLO, (u8) offset }; - + return _SPIWriteTransaction(type, cmd, 2, (void*) ((u8*) data), size); } int CardSPIWriteSaveData_16bit(CardSPIType type, u32 offset, const void* data, u32 size) { u8 cmd[3] = { type.chip->writeCommand, (u8)(offset >> 8), (u8) offset }; - + return _SPIWriteTransaction(type, cmd, 3, (void*) ((u8*) data), size); } int CardSPIWriteSaveData_24bit_write(CardSPIType type, u32 offset, const void* data, u32 size) { u8 cmd[4] = { type.chip->writeCommand, (u8)(offset >> 16), (u8)(offset >> 8), (u8) offset }; - + return _SPIWriteTransaction(type, cmd, 4, (void*) ((u8*) data), size); } @@ -270,60 +270,60 @@ int CardSPIWriteSaveData_24bit_erase_program(CardSPIType type, u32 offset, const int CardSPIWriteSaveData(CardSPIType type, u32 offset, const void* data, u32 size) { if (type.chip == NO_CHIP) return 1; - + if (size == 0) return 0; size = min(size, CardSPIGetCapacity(type) - offset); u32 end = offset + size; u32 pos = offset; u32 writeSize = type.chip->writeSize; if (writeSize == 0) return 0xC8E13404; - + int res = CardSPIWaitWriteEnd(type, 1000); if (res) return res; - + while(pos < end) { u32 remaining = end - pos; u32 nb = writeSize - (pos % writeSize); - + u32 dataSize = (remaining < nb) ? remaining : nb; - + if ((res = type.chip->writeSaveData(type, pos, (void*) ((u8*) data - offset + pos), dataSize))) return res; - + pos = ((pos / writeSize) + 1) * writeSize; // truncate } - + return 0; } -int CardSPIReadSaveData_9bit(CardSPIType type, u32 pos, void* data, u32 size) { +int CardSPIReadSaveData_9bit(CardSPIType type, u32 pos, void* data, u32 size) { u8 cmd[4]; u32 cmdSize = 2; - + u32 end = pos + size; - + u32 read = 0; if (pos < 0x100) { u32 len = 0x100 - pos; cmd[0] = SPI_512B_EEPROM_CMD_RDLO; cmd[1] = (u8) pos; - + int res = CardSPIWriteRead(type, cmd, cmdSize, data, len, NULL, 0); if (res) return res; - + read += len; } - + if (end >= 0x100) { u32 len = end - 0x100; cmd[0] = SPI_512B_EEPROM_CMD_RDHI; cmd[1] = (u8)(pos + read); - + int res = CardSPIWriteRead(type, cmd, cmdSize, (void*)((u8*)data + read), len, NULL, 0); if (res) return res; } - + return 0; } @@ -335,7 +335,7 @@ int CardSPIReadSaveData_16bit(CardSPIType type, u32 offset, void* data, u32 size int CardSPIReadSaveData_24bit(CardSPIType type, u32 offset, void* data, u32 size) { u8 cmd[4] = { SPI_CMD_READ, (u8)(offset >> 16), (u8)(offset >> 8), (u8) offset }; - + return CardSPIWriteRead(type, cmd, 4, data, size, NULL, 0); } @@ -343,10 +343,10 @@ int CardSPIReadSaveData(CardSPIType type, u32 offset, void* data, u32 size) { if (type.chip == NO_CHIP) return 1; if (size == 0) return 0; - + int res = CardSPIWaitWriteEnd(type, 1000); if (res) return res; - + size = (size <= CardSPIGetCapacity(type) - offset) ? size : CardSPIGetCapacity(type) - offset; return type.chip->readSaveData(type, offset, data, size); @@ -358,7 +358,7 @@ int CardSPIEraseSector_emulated(CardSPIType type, u32 offset) { if (!fill_buf) return 1; memset(fill_buf, 0xff, blockSize); offset = (offset / blockSize) * blockSize; - + int res = CardSPIWriteSaveData(type, offset, fill_buf, blockSize); free(fill_buf); return res; @@ -366,10 +366,10 @@ int CardSPIEraseSector_emulated(CardSPIType type, u32 offset) { int CardSPIEraseSector_real(CardSPIType type, u32 offset) { u8 cmd[4] = { type.chip->eraseCommand, (u8)(offset >> 16), (u8)(offset >> 8), (u8) offset }; - + int res = CardSPIWaitWriteEnd(type, 10000); if (res) return res; - + return _SPIWriteTransaction(type, cmd, 4, NULL, 0); } @@ -399,41 +399,41 @@ int CardSPIErase(CardSPIType type) { * * Copyright (C) Pokedoc (2010) */ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ - + int _SPIIsDataMirrored(CardSPIType type, int size, bool* mirrored) { u32 offset0 = (size-1); // n KB u32 offset1 = (2*size-1); // 2n KB - + u8 buf1; // +0k data read -> write u8 buf2; // +n k data read -> read u8 buf3; // +0k ~data write u8 buf4; // +n k data new comp buf2 - + int res; - + if ((res = CardSPIReadSaveData(type, offset0, &buf1, 1))) return res; if ((res = CardSPIReadSaveData(type, offset1, &buf2, 1))) return res; buf3=~buf1; if ((res = CardSPIWriteSaveData(type, offset0, &buf3, 1))) return res; if ((res = CardSPIReadSaveData(type, offset1, &buf4, 1))) return res; if ((res = CardSPIWriteSaveData(type, offset0, &buf1, 1))) return res; - + *mirrored = buf2 != buf4; return 0; } @@ -442,8 +442,8 @@ int CardSPIGetCardSPIType(CardSPIType* type, bool infrared) { u8 sr = 0; u32 jedec = 0; CardSPIType t = {NO_CHIP, infrared}; - int res; - + int res; + if(infrared) { // Infrared carts currently not supported, need additional handling! *type = (CardSPIType) {NO_CHIP, true}; @@ -452,20 +452,20 @@ int CardSPIGetCardSPIType(CardSPIType* type, bool infrared) { res = CardSPIReadJEDECIDAndStatusReg(t, &jedec, &sr); if (res) return res; - + if ((sr & 0xfd) == 0x00 && (jedec != 0x00ffffff)) { t.chip = &FLASH_DUMMY; } if ((sr & 0xfd) == 0xF0 && (jedec == 0x00ffffff)) { *type = (CardSPIType) { EEPROM_512B, false }; return 0; } if ((sr & 0xfd) == 0x00 && (jedec == 0x00ffffff)) { t = (CardSPIType) { &EEPROM_DUMMY, false }; } - + if(t.chip == NO_CHIP) { *type = (CardSPIType) {NO_CHIP, false}; return 0; } - + if (t.chip == &EEPROM_DUMMY) { bool mirrored = false; size_t i; - + for(i = 0; i < sizeof(EEPROMTypes) / sizeof(CardSPITypeData) - 1; i++) { if ((res = _SPIIsDataMirrored(t, CardSPIGetCapacity((CardSPIType) {EEPROMTypes + i, false}), &mirrored))) return res; if (mirrored) { @@ -476,15 +476,15 @@ int CardSPIGetCardSPIType(CardSPIType* type, bool infrared) { *type = (CardSPIType) { EEPROMTypes + i, false }; return 0; } - + for(size_t i = 0; i < sizeof(flashTypes) / sizeof(CardSPITypeData); i++) { if (flashTypes[i].jedecId == jedec) { *type = (CardSPIType) { flashTypes + i, infrared }; return 0; } } - + *type = (CardSPIType) { NO_CHIP, infrared }; return 0; - + } diff --git a/arm9/source/gamecart/card_spi.h b/arm9/source/gamecart/card_spi.h index 9ec15ea..359a7be 100644 --- a/arm9/source/gamecart/card_spi.h +++ b/arm9/source/gamecart/card_spi.h @@ -1,7 +1,7 @@ /* * This file is based on SPI.h from TWLSaveTool. Its copyright notice is * reproduced below. - * + * * Copyright (C) 2015-2016 TuxSH * * TWLSaveTool is free software: you can redistribute it and/or modify diff --git a/arm9/source/gamecart/command_ntr.c b/arm9/source/gamecart/command_ntr.c index 5d3ab79..7b6581a 100644 --- a/arm9/source/gamecart/command_ntr.c +++ b/arm9/source/gamecart/command_ntr.c @@ -42,9 +42,9 @@ void NTR_CmdReadHeader (u8* buffer) while(REG_NTRCARDROMCNT&NTRCARD_BUSY) ; u32 iCardId=cardReadID(NTRCARD_CLK_SLOW); while(REG_NTRCARDROMCNT&NTRCARD_BUSY) ; - + u32 iCheapCard=iCardId&0x80000000; - + if(iCheapCard) { //this is magic of wood goblins diff --git a/arm9/source/gamecart/gamecart.c b/arm9/source/gamecart/gamecart.c index 0f42599..f032c19 100644 --- a/arm9/source/gamecart/gamecart.c +++ b/arm9/source/gamecart/gamecart.c @@ -68,18 +68,18 @@ u32 InitCartRead(CartData* cdata) { cdata->cart_type = (cdata->cart_id & 0x10000000) ? CART_CTR : CART_NTR; if (cdata->cart_type & CART_CTR) { // CTR cartridges memset(cdata, 0xFF, 0x4000 + PRIV_HDR_SIZE); // switch the padding to 0xFF - + // init, NCCH header static u32 sec_keys[4]; u8* ncch_header = cdata->header + 0x1000; CTR_CmdReadHeader(ncch_header); Cart_Secure_Init((u32*) (void*) ncch_header, sec_keys); - + // NCSD header and CINFO // Cart_Dummy(); // Cart_Dummy(); CTR_CmdReadData(0, 0x200, 8, cdata->header); - + // safety checks, cart size NcsdHeader* ncsd = (NcsdHeader*) (void*) cdata->header; NcchHeader* ncch = (NcchHeader*) (void*) ncch_header; @@ -90,14 +90,14 @@ u32 InitCartRead(CartData* cdata) { if (cdata->cart_size > 0x100000000) return 1; // carts > 4GB don't exist // else if (cdata->cart_size == 0x100000000) cdata->cart_size -= 0x200; // silent 4GB fix if (cdata->data_size > cdata->cart_size) return 1; - + // private header u8* priv_header = cdata->header + 0x4000; CTR_CmdReadUniqueID(priv_header); memcpy(priv_header + 0x40, &(cdata->cart_id), 4); memset(priv_header + 0x44, 0x00, 4); memset(priv_header + 0x48, 0xFF, 8); - + // save data u32 card2_offset = getle32(cdata->header + 0x200); if ((card2_offset != 0xFFFFFFFF) || (CardSPIGetCardSPIType(&(cdata->save_type), 0) != 0)) { @@ -110,13 +110,13 @@ u32 InitCartRead(CartData* cdata) { NTR_CmdReadHeader(cdata->header); if (!(*(cdata->header))) return 1; // error reading the header if (!NTR_Secure_Init(cdata->header, Cart_GetID(), 0)) return 1; - + // cartridge size, trimmed size, twl presets if (nds_header->device_capacity >= 15) return 1; // too big, not valid cdata->cart_size = (128 * 1024) << nds_header->device_capacity; cdata->data_size = nds_header->ntr_rom_size; cdata->arm9i_rom_offset = 0; - + // TWL header if (nds_header->unit_code != 0x00) { // DSi or NDS+DSi cdata->cart_type |= CART_TWL; @@ -129,10 +129,10 @@ u32 InitCartRead(CartData* cdata) { NTR_CmdReadHeader(cdata->twl_header); if (!NTR_Secure_Init(cdata->twl_header, Cart_GetID(), 1)) return 1; } - + // last safety check if (cdata->data_size > cdata->cart_size) return 1; - + // save data bool infrared = *(nds_header->game_code) == 'I'; if (CardSPIGetCardSPIType(&(cdata->save_type), infrared) != 0) { @@ -203,7 +203,7 @@ u32 ReadCartSectors(void* buffer, u32 sector, u32 count, CartData* cdata) { } u32 ReadCartBytes(void* buffer, u64 offset, u64 count, CartData* cdata) { - if (!(offset % 0x200) && !(count % 0x200)) { // aligned data -> simple case + if (!(offset % 0x200) && !(count % 0x200)) { // aligned data -> simple case // simple wrapper function for ReadCartSectors(...) return ReadCartSectors(buffer, offset / 0x200, count / 0x200, cdata); } else { // misaligned data -> -___- diff --git a/arm9/source/gamecart/secure_ntr.c b/arm9/source/gamecart/secure_ntr.c index 29f0ff6..55e91ec 100644 --- a/arm9/source/gamecart/secure_ntr.c +++ b/arm9/source/gamecart/secure_ntr.c @@ -129,7 +129,7 @@ void NTR_InitKey (u32 aGameCode, u32* pCardHash, int nCardHash, u32* pKeyCode, i const u8* BlowfishNtr = (const u8*)0x01FFE428; memcpy (pCardHash, BlowfishNtr, 0x1048); } - + pKeyCode[0] = aGameCode; pKeyCode[1] = aGameCode/2; pKeyCode[2] = aGameCode*2; @@ -202,7 +202,7 @@ void NTR_SecureDelay(u16 aTimeout) //TIMER0_CR=TIMER_DIV_256|TIMER_ENABLE; TIMER0_CR=TIMER_DIV_1024|TIMER_ENABLE; while(TIMER0_DATA!=0xFFFF); - + // Clear out the timer registers TIMER0_CR=0; TIMER0_DATA=0; diff --git a/arm9/source/godmode.c b/arm9/source/godmode.c index 5965019..7cf0f99 100644 --- a/arm9/source/godmode.c +++ b/arm9/source/godmode.c @@ -183,7 +183,7 @@ void CheckBattery(u32* battery, bool* is_charging) { } *battery = battery_l; } - + if (is_charging) { static bool is_charging_l = false; static u64 timer_c = (u64) -1; @@ -200,19 +200,19 @@ void DrawBatteryBitmap(u16* screen, u32 b_x, u32 b_y, u32 width, u32 height) { const u16 color_inline = COLOR_LIGHTGREY; const u16 color_inside = COLOR_LIGHTERGREY; const u16 color_bg = COLOR_TRANSPARENT; - + if ((width < 8) || (height < 6)) return; - + u32 battery; bool is_charging; CheckBattery(&battery, &is_charging); - + u16 color_battery = (is_charging) ? COLOR_BATTERY_CHARGING : (battery > 70) ? COLOR_BATTERY_FULL : (battery > 30) ? COLOR_BATTERY_MEDIUM : COLOR_BATTERY_LOW; u32 nub_size = (height < 12) ? 1 : 2; u32 width_inside = width - 4 - nub_size; u32 width_battery = (battery >= 100) ? width_inside : ((battery * width_inside) + 50) / 100; - + for (u32 y = 0; y < height; y++) { const u32 mirror_y = (y >= (height+1) / 2) ? height - 1 - y : y; for (u32 x = 0; x < width; x++) { @@ -233,14 +233,14 @@ void DrawTopBar(const char* curr_path) { const u32 bartxt_x = 2; const u32 len_path = SCREEN_WIDTH_TOP - 120; char tempstr[64]; - + // top bar - current path DrawRectangle(TOP_SCREEN, 0, 0, SCREEN_WIDTH_TOP, 12, COLOR_TOP_BAR); if (*curr_path) TruncateString(tempstr, curr_path, min(63, len_path / FONT_WIDTH_EXT), 8); else snprintf(tempstr, 16, "[root]"); DrawStringF(TOP_SCREEN, bartxt_x, bartxt_start, COLOR_STD_BG, COLOR_TOP_BAR, "%s", tempstr); bool show_time = true; - + #ifdef SHOW_FREE if (*curr_path) { // free & total storage const u32 bartxt_rx = SCREEN_WIDTH_TOP - (19*FONT_WIDTH_EXT) - bartxt_x; @@ -262,14 +262,14 @@ void DrawTopBar(const char* curr_path) { show_time = false; } #endif - + if (show_time) { // clock & battery const u32 battery_width = 16; const u32 battery_height = 9; const u32 battery_x = SCREEN_WIDTH_TOP - battery_width - bartxt_x; const u32 battery_y = (12 - battery_height) / 2; const u32 clock_x = battery_x - (15*FONT_WIDTH_EXT); - + char timestr[32]; GetTimeString(timestr, false, false); DrawStringF(TOP_SCREEN, clock_x, bartxt_start, COLOR_STD_BG, COLOR_TOP_BAR, "%14.14s", timestr); @@ -284,7 +284,7 @@ void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, u32 curr_pan const u32 len_info = (SCREEN_WIDTH_MAIN - ((SCREEN_WIDTH_MAIN >= 400) ? 80 : 20)) / 2; const u32 str_len_info = min(63, len_info / FONT_WIDTH_EXT); char tempstr[64]; - + static u32 state_prev = 0xFFFFFFFF; u32 state_curr = ((*curr_path) ? (1<<0) : 0) | @@ -293,12 +293,12 @@ void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, u32 curr_pan ((GetMountState()) ? (1<<3) : 0) | ((GetWritePermissions() > PERM_BASE) ? (1<<4) : 0) | (curr_pane<<5); - + if (state_prev != state_curr) { ClearScreenF(true, false, COLOR_STD_BG); state_prev = state_curr; } - + // left top - current file info if (curr_pane) snprintf(tempstr, 63, "PANE #%lu", curr_pane); else snprintf(tempstr, 63, "CURRENT"); @@ -315,7 +315,7 @@ void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, u32 curr_pan } else if (curr_entry->type == T_ROOT) { int drvtype = DriveType(curr_entry->path); char drvstr[32]; - snprintf(drvstr, 31, "(%s%s)", + snprintf(drvstr, 31, "(%s%s)", ((drvtype & DRV_SDCARD) ? "SD" : (drvtype & DRV_RAMDRIVE) ? "RAMdrive" : (drvtype & DRV_GAME) ? "Game" : (drvtype & DRV_SYSNAND) ? "SysNAND" : (drvtype & DRV_EMUNAND) ? "EmuNAND" : (drvtype & DRV_IMAGE) ? "Image" : (drvtype & DRV_XORPAD) ? "XORpad" : (drvtype & DRV_MEMORY) ? "Memory" : (drvtype & DRV_ALIAS) ? "Alias" : @@ -341,7 +341,7 @@ void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, u32 curr_pan ResizeString(tempstr, "", str_len_info, 8, false); DrawStringF(MAIN_SCREEN, 4, info_start + 12 + 10 + 10, color_current, COLOR_STD_BG, "%s", tempstr); } - + // right top - clipboard DrawStringF(MAIN_SCREEN, SCREEN_WIDTH_MAIN - len_info, info_start, COLOR_STD_FONT, COLOR_STD_BG, "%*s", len_info / FONT_WIDTH_EXT, (clipboard->n_entries) ? "[CLIPBOARD]" : ""); @@ -354,7 +354,7 @@ void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, u32 curr_pan if (clipboard->n_entries > n_cb_show) snprintf(tempstr, 60, "+ %lu more", clipboard->n_entries - n_cb_show); DrawStringF(MAIN_SCREEN, SCREEN_WIDTH_MAIN - len_info - 4, info_start + 12 + (n_cb_show*10), COLOR_DARKGREY, COLOR_STD_BG, "%*s", len_info / FONT_WIDTH_EXT, tempstr); - + // bottom: instruction block char instr[512]; snprintf(instr, 512, "%s\n%s%s%s%s%s%s%s%s", @@ -364,7 +364,7 @@ void DrawUserInterface(const char* curr_path, DirEntry* curr_entry, u32 curr_pan ((GetWritePermissions() > PERM_BASE) ? "R+Y - Relock write permissions\n" : ""), (*curr_path) ? "" : (GetMountState()) ? "R+X - Unmount image\n" : "", (*curr_path) ? "" : (CheckSDMountState()) ? "R+B - Unmount SD card\n" : "R+B - Remount SD card\n", - (*curr_path) ? "R+A - Directory options\n" : "R+A - Drive options\n", + (*curr_path) ? "R+A - Directory options\n" : "R+A - Drive options\n", "R+L - Make a Screenshot\n", "R+\x1B\x1A - Switch to prev/next pane\n", (clipboard->n_entries) ? "SELECT - Clear Clipboard\n" : "SELECT - Restore Clipboard\n", // only if clipboard is full @@ -379,12 +379,12 @@ void DrawDirContents(DirStruct* contents, u32 cursor, u32* scroll) { const u32 pos_x = 0; const u32 lines = (SCREEN_HEIGHT-(start_y+2)+(stp_y-1)) / stp_y; u32 pos_y = start_y + 2; - + if (*scroll > cursor) *scroll = cursor; else if (*scroll + lines <= cursor) *scroll = cursor - lines + 1; if (*scroll + lines > contents->n_entries) *scroll = (contents->n_entries > lines) ? contents->n_entries - lines : 0; - + for (u32 i = 0; pos_y < SCREEN_HEIGHT; i++) { char tempstr[str_width + 1]; u32 offset_i = *scroll + i; @@ -402,7 +402,7 @@ void DrawDirContents(DirStruct* contents, u32 cursor, u32* scroll) { DrawStringF(ALT_SCREEN, pos_x, pos_y, color_font, COLOR_STD_BG, "%s", tempstr); pos_y += stp_y; } - + const u32 flist_height = (SCREEN_HEIGHT - start_y); const u32 bar_width = 2; if (contents->n_entries > lines) { // draw position bar at the right @@ -410,7 +410,7 @@ void DrawDirContents(DirStruct* contents, u32 cursor, u32* scroll) { u32 bar_height = (lines * flist_height) / contents->n_entries; if (bar_height < bar_height_min) bar_height = bar_height_min; const u32 bar_pos = ((u64) *scroll * (flist_height - bar_height)) / (contents->n_entries - lines) + start_y; - + DrawRectangle(ALT_SCREEN, SCREEN_WIDTH_ALT - bar_width, start_y, bar_width, (bar_pos - start_y), COLOR_STD_BG); DrawRectangle(ALT_SCREEN, SCREEN_WIDTH_ALT - bar_width, bar_pos + bar_height, bar_width, SCREEN_HEIGHT - (bar_pos + bar_height), COLOR_STD_BG); DrawRectangle(ALT_SCREEN, SCREEN_WIDTH_ALT - bar_width, bar_pos, bar_width, bar_height, COLOR_SIDE_BAR); @@ -431,14 +431,14 @@ u32 SdFormatMenu(const char* slabel) { u64 sdcard_size_mb = 0; u64 emunand_size_mb = (u64) -1; u32 user_select; - + // check actual SD card size sdcard_size_mb = GetSDCardSize() / 0x100000; if (!sdcard_size_mb) { ShowPrompt(false, "Error: SD card not detected."); return 1; } - + user_select = ShowSelectPrompt(7, option_emunand_size, "Format SD card (%lluMB)?\nChoose EmuNAND size:", sdcard_size_mb); if (user_select && (user_select < 4)) { emunand_size_mb = (user_select == 2) ? sysnand_min_size_mb : (user_select == 3) ? sysnand_size_mb : 0; @@ -450,20 +450,20 @@ u32 SdFormatMenu(const char* slabel) { if (emunand_size_mb == (u64) -1) break; } while (emunand_size_mb > sdcard_size_mb); if (emunand_size_mb == (u64) -1) return 1; - + user_select = ShowSelectPrompt(4, option_cluster_size, "Format SD card (%lluMB)?\nChoose cluster size:", sdcard_size_mb); if (!user_select) return 1; else cluster_size = cluster_size_table[user_select]; - + snprintf(label, DRV_LABEL_LEN + 4, "0:%s", (slabel && *slabel) ? slabel : "GM9SD"); if (!ShowKeyboardOrPrompt(label + 2, 11 + 1, "Format SD card (%lluMB)?\nEnter label:", sdcard_size_mb)) return 1; - + if (!FormatSDCard(emunand_size_mb, cluster_size, label)) { ShowPrompt(false, "Format SD: failed!"); return 1; } - + if (emunand_size_mb >= sysnand_min_size_mb) { u32 emunand_offset = 1; u32 n_emunands = 1; @@ -480,13 +480,13 @@ u32 SdFormatMenu(const char* slabel) { emunand_offset = (user_select == 2) ? 0 : 1; // 0 -> GW EmuNAND } else user_select = ShowPrompt(true, "Clone SysNAND to RedNAND?") ? 1 : 0; if (!user_select) return 0; - + u8 ncsd[0x200]; u32 flags = OVERRIDE_PERM; InitSDCardFS(); // this has to be initialized for EmuNAND to work for (u32 i = 0; i < n_emunands; i++) { if ((i * sysnand_multi_size_mb) + sysnand_min_size_mb > emunand_size_mb) break; - SetEmuNandBase((i * sysnand_multi_size_mb * 0x100000 / 0x200) + emunand_offset); + SetEmuNandBase((i * sysnand_multi_size_mb * 0x100000 / 0x200) + emunand_offset); if ((ReadNandSectors(ncsd, 0, 1, 0xFF, NAND_SYSNAND) != 0) || (WriteNandSectors(ncsd, 0, 1, 0xFF, NAND_EMUNAND) != 0) || (!PathCopy("E:", "S:/nand_minsize.bin", &flags))) { @@ -496,7 +496,7 @@ u32 SdFormatMenu(const char* slabel) { } DeinitSDCardFS(); } - + return 0; } @@ -539,51 +539,51 @@ u32 FileHexViewer(const char* path) { u8* data = NULL; u8* bottom_cpy = (u8*) malloc(SCREEN_SIZE_BOT); // a copy of the bottom screen framebuffer u32 fsize = FileGetSize(path); - + bool dual_screen = 0; int x_off = 0, x_hex = 0, x_ascii = 0; u32 vpad = 0, hlpad = 0, hrpad = 0; u32 rows = 0, cols = 0; u32 total_shown = 0; u32 total_data = 0; - + u32 last_mode = 0xFF; u32 last_offset = (u32) -1; u32 offset = 0; - + u8 found_data[64 + 1] = { 0 }; u32 found_offset = (u32) -1; u32 found_size = 0; - + static const u32 edit_bsize = 0x4000; // should be multiple of 0x200 * 2 bool edit_mode = false; u8* buffer = (u8*) malloc(edit_bsize); u8* buffer_cpy = (u8*) malloc(edit_bsize); u32 edit_start = 0; int cursor = 0; - + if (!bottom_cpy || !buffer || !buffer_cpy) { if (bottom_cpy) free(bottom_cpy); if (buffer) free(buffer); if (buffer_cpy) free(buffer_cpy); return 1; } - + static bool show_instr = true; static const char* instr = "Hexeditor Controls:\n \n\x18\x19\x1A\x1B(+R) - Scroll\nR+Y - Switch view\nX - Search / goto...\nA - Enter edit mode\nA+\x18\x19\x1A\x1B - Edit value\nB - Exit\n"; if (show_instr) { // show one time instructions ShowPrompt(false, instr); show_instr = false; } - + if (MAIN_SCREEN != TOP_SCREEN) ShowString(instr); memcpy(bottom_cpy, BOT_SCREEN, SCREEN_SIZE_BOT); - + data = buffer; while (true) { if (mode != last_mode) { if (FONT_WIDTH_EXT <= 5) { - mode = 0; + mode = 0; vpad = 1; hlpad = hrpad = 2; cols = 16; @@ -602,7 +602,7 @@ u32 FileHexViewer(const char* path) { x_hex = x_off + (8*FONT_WIDTH_EXT) + 16; dual_screen = false; } else { - mode = 0; + mode = 0; vpad = 0; hlpad = hrpad = 3; cols = 8; @@ -641,7 +641,7 @@ u32 FileHexViewer(const char* path) { dual_screen = false; break; default: - mode = 0; + mode = 0; vpad = hlpad = hrpad = 2; cols = 8; x_off = (SCREEN_WIDTH_TOP - SCREEN_WIDTH_BOT) / 2; @@ -673,7 +673,7 @@ u32 FileHexViewer(const char* path) { } last_offset = offset; } - + // display data on screen for (u32 row = 0; row < rows; row++) { char ascii[16 + 1] = { 0 }; @@ -682,29 +682,29 @@ u32 FileHexViewer(const char* path) { u32 cutoff = (curr_pos >= total_data) ? 0 : (total_data >= curr_pos + cols) ? cols : total_data - curr_pos; u16* screen = TOP_SCREEN; u32 x0 = 0; - + // marked offsets handling s32 marked0 = 0, marked1 = 0; if ((found_size > 0) && - (found_offset + found_size > offset + curr_pos) && + (found_offset + found_size > offset + curr_pos) && (found_offset < offset + curr_pos + cols)) { marked0 = (s32) found_offset - (offset + curr_pos); marked1 = marked0 + found_size; if (marked0 < 0) marked0 = 0; if (marked1 > cols) marked1 = cols; } - + // switch to bottom screen if (y >= SCREEN_HEIGHT) { y -= SCREEN_HEIGHT; screen = BOT_SCREEN; x0 = 40; } - + memcpy(ascii, data + curr_pos, cols); for (u32 col = 0; col < cols; col++) if ((col >= cutoff) || (ascii[col] == 0x00)) ascii[col] = ' '; - + // draw offset / ASCII representation if (x_off >= 0) DrawStringF(screen, x_off - x0, y, cutoff ? COLOR_HVOFFS : COLOR_HVOFFSI, COLOR_STD_BG, "%08X", (unsigned int) offset + curr_pos); @@ -715,7 +715,7 @@ u32 FileHexViewer(const char* path) { if (edit_mode && ((u32) cursor / cols == row)) DrawCharacter(screen, ascii[cursor % cols], x_ascii - x0 + FONT_WIDTH_EXT * (cursor % cols), y, COLOR_RED, COLOR_STD_BG); } - + // draw HEX values for (u32 col = 0; (col < cols) && (x_hex >= 0); col++) { u32 x = (x_hex + hlpad) + (((2*FONT_WIDTH_EXT) + hrpad + hlpad) * col) - x0; @@ -726,7 +726,7 @@ u32 FileHexViewer(const char* path) { else DrawStringF(screen, x, y, hex_color, COLOR_STD_BG, " "); } } - + // handle user input u32 pad_state = InputWait(0); if (!edit_mode) { // standard viewer mode @@ -750,7 +750,7 @@ u32 FileHexViewer(const char* path) { else memcpy(BOT_SCREEN, bottom_cpy, SCREEN_SIZE_BOT); } else if (pad_state & BUTTON_X) { static const char* optionstr[3] = { "Go to offset", "Search for string", "Search for data" }; - u32 user_select = ShowSelectPrompt(3, optionstr, "Current offset: %08X\nSelect action:", + u32 user_select = ShowSelectPrompt(3, optionstr, "Current offset: %08X\nSelect action:", (unsigned int) offset); if (user_select == 1) { // -> goto offset u64 new_offset = ShowHexPrompt(offset, 8, "Current offset: %08X\nEnter new offset below.", @@ -785,7 +785,7 @@ u32 FileHexViewer(const char* path) { found_size = 0; found_offset = (u32) -1; cursor = 0; - edit_start = ((offset - (offset % 0x200) <= (edit_bsize / 2)) || (fsize < edit_bsize)) ? 0 : + edit_start = ((offset - (offset % 0x200) <= (edit_bsize / 2)) || (fsize < edit_bsize)) ? 0 : offset - (offset % 0x200) - (edit_bsize / 2); FileGetData(path, buffer, edit_bsize, edit_start); memcpy(buffer_cpy, buffer, edit_bsize); @@ -831,11 +831,11 @@ u32 FileHexViewer(const char* path) { } } } - + ClearScreen(TOP_SCREEN, COLOR_STD_BG); if (MAIN_SCREEN == TOP_SCREEN) memcpy(BOT_SCREEN, bottom_cpy, SCREEN_SIZE_BOT); else ClearScreen(BOT_SCREEN, COLOR_STD_BG); - + free(bottom_cpy); free(buffer); free(buffer_cpy); @@ -855,7 +855,7 @@ u32 Sha256Calculator(const char* path) { static u8 sha256_prev[32] = { 0 }; char sha_path[256]; u8 sha256_file[32]; - + snprintf(sha_path, 256, "%s.sha", path); bool have_sha = (FileGetData(sha_path, sha256_file, 32, 0) == 32); bool match_sha = have_sha && (memcmp(sha256, sha256_file, 32) == 0); @@ -870,11 +870,11 @@ u32 Sha256Calculator(const char* path) { (write_sha) ? "\n \nWrite .SHA file?" : "") && write_sha) { FileSetData(sha_path, sha256, 32, 0, true); } - + strncpy(pathstr_prev, pathstr, 32 + 1); memcpy(sha256_prev, sha256, 32); } - + return 0; } @@ -906,8 +906,8 @@ u32 CmacCalculator(const char* path) { ShowPrompt(false, "Fixing CMAC: failed!"); } } - - + + return 0; } @@ -915,16 +915,16 @@ u32 StandardCopy(u32* cursor, u32* scroll) { DirEntry* curr_entry = &(current_dir->entry[*cursor]); u32 n_marked = 0; if (curr_entry->marked) { - for (u32 i = 0; i < current_dir->n_entries; i++) + for (u32 i = 0; i < current_dir->n_entries; i++) if (current_dir->entry[i].marked) n_marked++; } - + u32 flags = BUILD_PATH; if ((n_marked > 1) && ShowPrompt(true, "Copy all %lu selected items?", n_marked)) { u32 n_success = 0; for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; flags |= ASK_ALL; DrawDirContents(current_dir, (*cursor = i), scroll); @@ -945,7 +945,7 @@ u32 StandardCopy(u32* cursor, u32* scroll) { ShowPrompt(false, "%s\nFailed copying item", pathstr); else ShowPrompt(false, "%s\nCopied to %s", pathstr, OUTPUT_PATH); } - + return 0; } @@ -960,7 +960,7 @@ u32 DirFileAttrMenu(const char* path, const char *name) { TruncateString(namestr, name, 31, 8); // preparations: create file info, date string - if (!drv) { + if (!drv) { if (fvx_stat(path, &fno) != FR_OK) return 1; vrt = (fno.fattrib & AM_VRT); new_attrib = fno.fattrib; @@ -1071,18 +1071,18 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan const char* file_path = (&(current_dir->entry[*cursor]))->path; const char* file_name = (&(current_dir->entry[*cursor]))->name; const char* optionstr[16]; - + // check for file lock if (!FileUnlock(file_path)) return 1; - + u64 filetype = IdentifyFileType(file_path); u32 drvtype = DriveType(file_path); - + bool in_output_path = (strncasecmp(current_path, OUTPUT_PATH, 256) == 0); - + // don't handle TMDs inside the game drive, won't work properly anyways if ((filetype & GAME_TMD) && (drvtype & DRV_GAME)) filetype &= ~GAME_TMD; - + // special stuff, only available for known filetypes (see int special below) bool mountable = (FTYPE_MOUNTABLE(filetype) && !(drvtype & DRV_IMAGE) && !((drvtype & (DRV_SYSNAND|DRV_EMUNAND)) && (drvtype & DRV_VIRTUAL) && (filetype & IMG_FAT))); @@ -1100,7 +1100,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan bool key_buildable = (FTYPE_KEYBUILD(filetype)) && !in_output_path && !((drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); bool titleinfo = (FTYPE_TITLEINFO(filetype)); - bool ciacheckable = (FTYPE_CIACHECK(filetype)); + bool ciacheckable = (FTYPE_CIACHECK(filetype)); bool renamable = (FTYPE_RENAMABLE(filetype)) && !(drvtype & DRV_VIRTUAL) && !(drvtype & DRV_ALIAS) && !(drvtype & DRV_CTRNAND) && !(drvtype & DRV_TWLNAND) && !(drvtype & DRV_IMAGE); bool trimable = (FTYPE_TRIMABLE(filetype)) && !(drvtype & DRV_VIRTUAL) && !(drvtype & DRV_ALIAS) && @@ -1122,7 +1122,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan bool installable = (FTYPE_INSTALLABLE(filetype)); bool agbexportable = (FTYPE_AGBSAVE(filetype) && (drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); bool agbimportable = (FTYPE_AGBSAVE(filetype) && (drvtype & DRV_VIRTUAL) && (drvtype & DRV_SYSNAND)); - + char cxi_path[256] = { 0 }; // special options for TMD if ((filetype & GAME_TMD) && !(filetype & FLAG_NUSCDN) && (GetTmdContentPath(cxi_path, file_path) == 0) && @@ -1131,18 +1131,18 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan mountable = (FTYPE_MOUNTABLE(filetype_cxi) && !(drvtype & DRV_IMAGE)); extrcodeable = (FTYPE_HASCODE(filetype_cxi)); } - + bool special_opt = mountable || verificable || decryptable || encryptable || cia_buildable || cia_buildable_legit || cxi_dumpable || tik_buildable || key_buildable || titleinfo || renamable || trimable || transferable || hsinjectable || restorable || xorpadable || ebackupable || ncsdfixable || extrcodeable || keyinitable || keyinstallable || bootable || scriptable || fontable || viewable || installable || agbexportable || agbimportable; - + char pathstr[32+1]; TruncateString(pathstr, file_path, 32, 8); - + u32 n_marked = 0; if ((&(current_dir->entry[*cursor]))->marked) { - for (u32 i = 0; i < current_dir->n_entries; i++) + for (u32 i = 0; i < current_dir->n_entries; i++) if (current_dir->entry[i].marked) n_marked++; } - + // main menu processing int n_opt = 0; int special = (special_opt) ? ++n_opt : -1; @@ -1199,7 +1199,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan if (inject > 0) optionstr[inject-1] = "Inject data @offset"; if (searchdrv > 0) optionstr[searchdrv-1] = "Open containing folder"; if (titleman > 0) optionstr[titleman-1] = "Open title folder"; - + int user_select = ShowSelectPrompt(n_opt, optionstr, (n_marked > 1) ? "%s\n%(%lu files selected)" : "%s", pathstr, n_marked); if (user_select == hexviewer) { // -> show in hex viewer @@ -1307,7 +1307,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan else if (user_select != special) { return 1; } - + // stuff for special menu starts here n_opt = 0; int show_info = (titleinfo) ? ++n_opt : -1; @@ -1378,7 +1378,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan if (agbexport > 0) optionstr[agbexport-1] = "Dump GBA VC save"; if (agbimport > 0) optionstr[agbimport-1] = "Inject GBA VC save"; if (setup > 0) optionstr[setup-1] = "Set as default"; - + // auto select when there is only one option user_select = (n_opt <= 1) ? n_opt : (int) ShowSelectPrompt(n_opt, optionstr, (n_marked > 1) ? "%s\n%(%lu files selected)" : "%s", pathstr, n_marked); @@ -1387,13 +1387,13 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan if (clipboard->n_entries && (DriveType(clipboard->entry[0].path) & DRV_IMAGE)) clipboard->n_entries = 0; // remove last mounted image clipboard entries InitImgFS((filetype & GAME_TMD) ? cxi_path : file_path); - + const char* drv_path = NULL; // find path of mounted drive for (u32 i = 0; i < (sizeof(mnt_drv_paths) / sizeof(const char*)); i++) { if (DriveType((drv_path = mnt_drv_paths[i]))) break; drv_path = NULL; } - + if (!drv_path) { ShowPrompt(false, "Mounting image: failed"); InitImgFS(NULL); @@ -1405,7 +1405,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan (*pane)->scroll = *scroll; if (++*pane >= panedata + N_PANES) *pane -= N_PANES; } - + strncpy(current_path, drv_path, 256); GetDirContents(current_dir, current_path); *cursor = 1; @@ -1430,7 +1430,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan ShowString("Trying to decrypt %lu files...", n_marked); for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) { n_other++; @@ -1483,7 +1483,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan ShowString("Trying to encrypt %lu files...", n_marked); for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) { n_other++; @@ -1518,10 +1518,10 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan bool force_legit = (user_select == cia_build_legit); if ((n_marked > 1) && ShowPrompt(true, "Try to process all %lu selected files?", n_marked)) { u32 n_success = 0; - u32 n_other = 0; + u32 n_other = 0; for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) { n_other++; @@ -1579,7 +1579,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan ShowString("Trying to install %lu files...", n_marked); for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) { n_other++; @@ -1617,7 +1617,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan optionstr[0] = "Keep ticket & savegame"; optionstr[1] = "Uninstall everything"; optionstr[2] = "Abort uninstall"; - user_select = (int) (n_marked > 1) ? + user_select = (int) (n_marked > 1) ? ShowSelectPrompt(3, optionstr, "Uninstall %lu selected titles?", n_marked) : ShowSelectPrompt(3, optionstr, "%s\nUninstall selected title?", pathstr); full_uninstall = (user_select == 2); @@ -1655,7 +1655,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan u32 n_processed = 0; for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; if (!(filetype & (GAME_CIA|GAME_TMD|GAME_NCSD|GAME_NCCH)) && !ShowProgress(n_processed++, n_marked, path)) break; @@ -1679,7 +1679,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan } if (n_other) ShowPrompt(false, "%lu/%lu files verified ok\n%lu/%lu not of same type", n_success, n_marked, n_other, n_marked); - else ShowPrompt(false, "%lu/%lu files verified ok", n_success, n_marked); + else ShowPrompt(false, "%lu/%lu files verified ok", n_success, n_marked); } else { ShowString("%s\nVerifying file, please wait...", pathstr); if (filetype & IMG_NAND) { @@ -1712,9 +1712,9 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan if (BuildTitleKeyInfo(NULL, dec, true) == 0) { if (n_other) ShowPrompt(false, "%s\n%lu/%lu files processed\n%lu/%lu files ignored", path_out, n_success, n_marked, n_other, n_marked); - else ShowPrompt(false, "%s\n%lu/%lu files processed", path_out, n_success, n_marked); + else ShowPrompt(false, "%s\n%lu/%lu files processed", path_out, n_success, n_marked); } else ShowPrompt(false, "%s\nBuild database failed.", path_out); - } else ShowPrompt(false, "%s\nBuild database %s.", path_out, + } else ShowPrompt(false, "%s\nBuild database %s.", path_out, (BuildTitleKeyInfo(file_path, dec, true) == 0) ? "success" : "failed"); return 0; } @@ -1739,9 +1739,9 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan if (BuildKeyDb(NULL, true) == 0) { if (n_other) ShowPrompt(false, "%s\n%lu/%lu files processed\n%lu/%lu files ignored", path_out, n_success, n_marked, n_other, n_marked); - else ShowPrompt(false, "%s\n%lu/%lu files processed", path_out, n_success, n_marked); + else ShowPrompt(false, "%s\n%lu/%lu files processed", path_out, n_success, n_marked); } else ShowPrompt(false, "%s\nBuild database failed.", path_out); - } else ShowPrompt(false, "%s\nBuild database %s.", path_out, + } else ShowPrompt(false, "%s\nBuild database %s.", path_out, (BuildKeyDb(file_path, true) == 0) ? "success" : "failed"); return 0; } @@ -1755,7 +1755,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; u64 prevsize = 0; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; if (!ShowProgress(n_processed++, n_marked, path)) break; if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) { @@ -1858,7 +1858,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan u32 n_processed = 0; for (u32 i = 0; i < current_dir->n_entries; i++) { const char* path = current_dir->entry[i].path; - if (!current_dir->entry[i].marked) + if (!current_dir->entry[i].marked) continue; if (!ShowProgress(n_processed++, n_marked, path)) break; if (!(IdentifyFileType(path) & filetype & TYPE_BASE)) { @@ -1868,7 +1868,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan DrawDirContents(current_dir, (*cursor = i), scroll); if (filetype & GAME_TMD) { char cxi_pathl[256] = { 0 }; - if ((GetTmdContentPath(cxi_pathl, path) == 0) && PathExist(cxi_pathl) && + if ((GetTmdContentPath(cxi_pathl, path) == 0) && PathExist(cxi_pathl) && (ExtractCodeFromCxiFile(cxi_pathl, NULL, NULL) == 0)) { n_success++; } else continue; @@ -1880,7 +1880,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan } if (n_other) ShowPrompt(false, "%lu/%lu files extracted ok\n%lu/%lu not of same type", n_success, n_marked, n_other, n_marked); - else ShowPrompt(false, "%lu/%lu files extracted ok", n_success, n_marked); + else ShowPrompt(false, "%lu/%lu files extracted ok", n_success, n_marked); } else { char extstr[8] = { 0 }; ShowString("%s\nExtracting .code, please wait...", pathstr); @@ -1926,7 +1926,7 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan bool inplace = (user_select == xorpad_inplace); bool success = (BuildNcchInfoXorpads((inplace) ? current_path : OUTPUT_PATH, file_path) == 0); ShowPrompt(false, "%s\nNCCHinfo padgen %s%s", pathstr, - (success) ? "success" : "failed", + (success) ? "success" : "failed", (!success || inplace) ? "" : "\nOutput dir: " OUTPUT_PATH); GetDirContents(current_dir, current_path); for (; *cursor < current_dir->n_entries; (*cursor)++) { @@ -2019,14 +2019,14 @@ u32 FileHandlerMenu(char* current_path, u32* cursor, u32* scroll, PaneData** pan } return 0; } - + return FileHandlerMenu(current_path, cursor, scroll, pane); } u32 HomeMoreMenu(char* current_path) { NandPartitionInfo np_info; if (GetNandPartitionInfo(&np_info, NP_TYPE_BONUS, NP_SUBTYPE_CTR, 0, NAND_SYSNAND) != 0) np_info.count = 0; - + const char* optionstr[8]; const char* promptstr = "HOME more... menu.\nSelect action:"; u32 n_opt = 0; @@ -2040,7 +2040,7 @@ u32 HomeMoreMenu(char* current_path) { int calib = ++n_opt; int sysinfo = ++n_opt; int readme = (FindVTarFileInfo(VRAM0_README_MD, NULL)) ? (int) ++n_opt : -1; - + if (sdformat > 0) optionstr[sdformat - 1] = "SD format menu"; if (bonus > 0) optionstr[bonus - 1] = "Bonus drive setup"; if (multi > 0) optionstr[multi - 1] = "Switch EmuNAND"; @@ -2051,7 +2051,7 @@ u32 HomeMoreMenu(char* current_path) { if (calib > 0) optionstr[calib - 1] = "Calibrate touchscreen"; if (sysinfo > 0) optionstr[sysinfo - 1] = "System info"; if (readme > 0) optionstr[readme - 1] = "Show ReadMe"; - + int user_select = ShowSelectPrompt(n_opt, optionstr, promptstr); if (user_select == sdformat) { // format SD card bool sd_state = CheckSDMountState(); @@ -2178,27 +2178,27 @@ u32 HomeMoreMenu(char* current_path) { MemToCViewer(README_md, README_md_size, "GodMode9 ReadMe Table of Contents"); return 0; } else return 1; - + return HomeMoreMenu(current_path); } u32 GodMode(int entrypoint) { const u32 quick_stp = (MAIN_SCREEN == TOP_SCREEN) ? 20 : 19; u32 exit_mode = GODMODE_EXIT_POWEROFF; - + char current_path[256] = { 0x00 }; u32 cursor = 0; u32 scroll = 0; - + int mark_next = -1; u32 last_write_perm = GetWritePermissions(); u32 last_clipboard_size = 0; - + bool bootloader = IS_UNLOCKED && (entrypoint == ENTRY_NANDBOOT); bool bootmenu = bootloader && (BOOTMENU_KEY != BUTTON_START) && CheckButton(BOOTMENU_KEY); bool godmode9 = !bootloader; - + // FIRM from FCRAM handling FirmHeader* firm_in_mem = (FirmHeader*) __FIRMTMP_ADDR; // should be safe here if (bootloader) { // check for FIRM in FCRAM, but prevent bootloops @@ -2210,27 +2210,27 @@ u32 GodMode(int entrypoint) { memcpy(addr, "NOPE", 4); // to prevent bootloops } } - + // get mode string for splash screen const char* disp_mode = NULL; if (bootloader) disp_mode = "bootloader mode\nR+LEFT for menu"; else if (!IS_UNLOCKED && (entrypoint == ENTRY_NANDBOOT)) disp_mode = "oldloader mode"; else if (entrypoint == ENTRY_NTRBOOT) disp_mode = "ntrboot mode"; else if (entrypoint == ENTRY_UNKNOWN) disp_mode = "unknown mode"; - + bool show_splash = true; #ifdef SALTMODE show_splash = !bootloader; #endif - + // init font if (!SetFontFromPbm(NULL, 0)) return exit_mode; - + // show splash screen (if enabled) ClearScreenF(true, true, COLOR_STD_BG); if (show_splash) SplashInit(disp_mode); u64 timer = timer_start(); // for splash delay - + InitSDCardFS(); AutoEmuNandBase(true); InitNandCrypto(true); // (entrypoint != ENTRY_B9S); @@ -2252,7 +2252,7 @@ u32 GodMode(int entrypoint) { free(pbm); } } - + // check for embedded essential backup if (((entrypoint == ENTRY_NANDBOOT) || (entrypoint == ENTRY_B9S)) && !PathExist("S:/essential.exefs") && CheckGenuineNandNcsd() && @@ -2263,7 +2263,7 @@ u32 GodMode(int entrypoint) { ShowPrompt(false, "Backup embedded in SysNAND\nand written to " OUTPUT_PATH "."); } } - + // check internal clock if (IS_UNLOCKED) { // we could actually do this on any entrypoint DsTime dstime; @@ -2277,12 +2277,12 @@ u32 GodMode(int entrypoint) { ShowPrompt(false, "New RTC date&time is:\n%s\n \nHint: HOMEMENU time needs\nmanual adjustment after\nsetting the RTC.", timestr); } } - + // check aeskeydb.bin / key state if ((entrypoint != ENTRY_B9S) && (CheckRecommendedKeyDb(NULL) != 0)) { ShowPrompt(false, "WARNING:\nNot running from a boot9strap\ncompatible entrypoint. Not\neverything may work as expected.\n \nProvide the recommended\naeskeydb.bin file to make this\nwarning go away."); } - + #if defined(SALTMODE) show_splash = bootmenu = (bootloader && CheckButton(BOOTMENU_KEY)); if (show_splash) SplashInit("saltmode"); @@ -2317,7 +2317,7 @@ u32 GodMode(int entrypoint) { break; } } - + // bootloader handler if (bootloader) { const char* bootfirm_paths[] = { BOOTFIRM_PATHS }; @@ -2331,7 +2331,7 @@ u32 GodMode(int entrypoint) { ShowPrompt(false, "No bootable FIRM found.\nNow resuming GodMode9..."); godmode9 = true; } - + if (godmode9) { current_dir = (DirStruct*) malloc(sizeof(DirStruct)); clipboard = (DirStruct*) malloc(sizeof(DirStruct)); @@ -2340,13 +2340,13 @@ u32 GodMode(int entrypoint) { ShowPrompt(false, "Out of memory."); // just to be safe return exit_mode; } - + GetDirContents(current_dir, ""); clipboard->n_entries = 0; memset(panedata, 0x00, N_PANES * sizeof(PaneData)); ClearScreenF(true, true, COLOR_STD_BG); // clear splash } - + PaneData* pane = panedata; while (godmode9) { // this is the main loop // basic sanity checking @@ -2364,7 +2364,7 @@ u32 GodMode(int entrypoint) { } if (cursor >= current_dir->n_entries) // cursor beyond allowed range cursor = current_dir->n_entries - 1; - + int curr_drvtype = DriveType(current_path); DirEntry* curr_entry = &(current_dir->entry[cursor]); if ((mark_next >= 0) && (curr_entry->type != T_DOTDOT)) { @@ -2374,7 +2374,7 @@ u32 GodMode(int entrypoint) { DrawDirContents(current_dir, cursor, &scroll); DrawUserInterface(current_path, curr_entry, N_PANES ? pane - panedata + 1 : 0); DrawTopBar(current_path); - + // check write permissions if (~last_write_perm & GetWritePermissions()) { if (ShowPrompt(true, "Write permissions were changed.\nRelock them?")) SetWritePermissions(last_write_perm, false); @@ -2385,7 +2385,7 @@ u32 GodMode(int entrypoint) { // handle user input u32 pad_state = InputWait(3); bool switched = (pad_state & BUTTON_R1); - + // basic navigation commands if ((pad_state & BUTTON_A) && (curr_entry->type != T_FILE) && (curr_entry->type != T_DOTDOT)) { // for dirs if (switched && !(DriveType(curr_entry->path) & DRV_SEARCH)) { // search directory @@ -2444,8 +2444,8 @@ u32 GodMode(int entrypoint) { current_path[255] = '\0'; if (user_select == 2) { char* last_slash = strrchr(current_path, '/'); - if (last_slash) *last_slash = '\0'; - } + if (last_slash) *last_slash = '\0'; + } GetDirContents(current_dir, current_path); if (*current_path && (current_dir->n_entries > 1)) { cursor = 1; @@ -2465,7 +2465,7 @@ u32 GodMode(int entrypoint) { char old_path[256]; char* last_slash = strrchr(current_path, '/'); strncpy(old_path, current_path, 256); - if (last_slash) *last_slash = '\0'; + if (last_slash) *last_slash = '\0'; else *current_path = '\0'; GetDirContents(current_dir, current_path); if (*old_path && current_dir->n_entries) { @@ -2545,7 +2545,7 @@ u32 GodMode(int entrypoint) { } else if (!switched) { // standard unswitched command set if ((curr_drvtype & DRV_VIRTUAL) && (pad_state & BUTTON_X) && (*current_path != 'T')) { ShowPrompt(false, "Not allowed in virtual path"); - } else if (pad_state & BUTTON_X) { // delete a file + } else if (pad_state & BUTTON_X) { // delete a file u32 n_marked = 0; if (curr_entry->marked) { for (u32 c = 0; c < current_dir->n_entries; c++) @@ -2612,16 +2612,16 @@ u32 GodMode(int entrypoint) { TruncateString(namestr, clipboard->entry[c].name, 36, 12); flags &= ~ASK_ALL; if (c < clipboard->n_entries - 1) flags |= ASK_ALL; - if ((user_select == 1) && !PathCopy(current_path, clipboard->entry[c].path, &flags)) { + if ((user_select == 1) && !PathCopy(current_path, clipboard->entry[c].path, &flags)) { if (c + 1 < clipboard->n_entries) { if (!ShowPrompt(true, "Failed copying path:\n%s\nProcess remaining?", namestr)) break; } else ShowPrompt(false, "Failed copying path:\n%s", namestr); - } else if ((user_select == 2) && !PathMove(current_path, clipboard->entry[c].path, &flags)) { + } else if ((user_select == 2) && !PathMove(current_path, clipboard->entry[c].path, &flags)) { if (c + 1 < clipboard->n_entries) { if (!ShowPrompt(true, "Failed moving path:\n%s\nProcess remaining?", namestr)) break; } else ShowPrompt(false, "Failed moving path:\n%s", namestr); } - } + } clipboard->n_entries = 0; GetDirContents(current_dir, current_path); } @@ -2670,7 +2670,7 @@ u32 GodMode(int entrypoint) { } } } - + if (pad_state & BUTTON_START) { exit_mode = (switched || (pad_state & BUTTON_LEFT)) ? GODMODE_EXIT_POWEROFF : GODMODE_EXIT_REBOOT; break; @@ -2690,7 +2690,7 @@ u32 GodMode(int entrypoint) { if (scripts > 0) optionstr[scripts - 1] = "Scripts..."; if (payloads > 0) optionstr[payloads - 1] = "Payloads..."; if (more > 0) optionstr[more - 1] = "More..."; - + int user_select = 0; while ((user_select = ShowSelectPrompt(n_opt, optionstr, "%s button pressed.\nSelect action:", buttonstr)) && (user_select != poweroff) && (user_select != reboot)) { @@ -2715,11 +2715,11 @@ u32 GodMode(int entrypoint) { break; } } - - if (user_select == poweroff) { + + if (user_select == poweroff) { exit_mode = GODMODE_EXIT_POWEROFF; break; - } else if (user_select == reboot) { + } else if (user_select == reboot) { exit_mode = GODMODE_EXIT_REBOOT; break; } @@ -2746,15 +2746,15 @@ u32 GodMode(int entrypoint) { GetDirContents(current_dir, current_path); } } - - + + DeinitExtFS(); DeinitSDCardFS(); - + if (current_dir) free(current_dir); if (clipboard) free(clipboard); if (panedata) free(panedata); - + return exit_mode; } @@ -2764,7 +2764,7 @@ u32 ScriptRunner(int entrypoint) { if (!SetFontFromPbm(NULL, 0)) return GODMODE_EXIT_POWEROFF; SplashInit("scriptrunner mode"); u64 timer = timer_start(); - + InitSDCardFS(); AutoEmuNandBase(true); InitNandCrypto(entrypoint != ENTRY_B9S); @@ -2776,14 +2776,14 @@ u32 ScriptRunner(int entrypoint) { s32 brightness = -1; if (LoadSupportFile("gm9bright.cfg", &brightness, 0x4)) SetScreenBrightness(brightness); - + while (CheckButton(BOOTPAUSE_KEY)); // don't continue while these keys are held while (timer_msec( timer ) < 500); // show splash for at least 0.5 sec // you didn't really install a scriptrunner to NAND, did you? if (IS_UNLOCKED && (entrypoint == ENTRY_NANDBOOT)) BootFirmHandler("0:/iderped.firm", false, false); - + if (PathExist("V:/" VRAM0_AUTORUN_GM9)) { ClearScreenF(true, true, COLOR_STD_BG); // clear splash ExecuteGM9Script("V:/" VRAM0_AUTORUN_GM9); @@ -2792,11 +2792,11 @@ u32 ScriptRunner(int entrypoint) { if (FileSelector(loadpath, FLAVOR " scripts menu.\nSelect script:", "V:/" VRAM0_SCRIPTS, "*.gm9", HIDE_EXT, false)) ExecuteGM9Script(loadpath); } else ShowPrompt(false, "Compiled as script autorunner\nbut no script provided.\n \nDerp!"); - + // deinit DeinitExtFS(); DeinitSDCardFS(); - + return GODMODE_EXIT_REBOOT; } #endif diff --git a/arm9/source/nand/essentials.h b/arm9/source/nand/essentials.h index dbefeb3..0080cdd 100644 --- a/arm9/source/nand/essentials.h +++ b/arm9/source/nand/essentials.h @@ -23,7 +23,7 @@ typedef struct { // see: http://3dbrew.org/wiki/Nand/private/movable.sed typedef struct { u8 magic[0x4]; // "SEED" - u8 indicator[0x4]; // uninitialized all zero, otherwise u8[1] nonzero + u8 indicator[0x4]; // uninitialized all zero, otherwise u8[1] nonzero LocalFriendCodeSeed codeseed_data; u8 keyy_high[8]; u8 unknown[0x10]; diff --git a/arm9/source/nand/nand.c b/arm9/source/nand/nand.c index 8748a57..b8fd588 100644 --- a/arm9/source/nand/nand.c +++ b/arm9/source/nand/nand.c @@ -33,7 +33,7 @@ static const u8 ALIGN(4) slot0x05KeyY_sha256[0x20] = { // hash for slot0x05KeyY }; static const u8 ALIGN(4) slot0x11Key95_sha256[0x20] = { // slot0x11Key95 hash (first 16 byte of sector0x96) - 0xBA, 0xC1, 0x40, 0x9C, 0x6E, 0xE4, 0x1F, 0x04, 0xAA, 0xC4, 0xE2, 0x09, 0x5C, 0xE9, 0x4F, 0x78, + 0xBA, 0xC1, 0x40, 0x9C, 0x6E, 0xE4, 0x1F, 0x04, 0xAA, 0xC4, 0xE2, 0x09, 0x5C, 0xE9, 0x4F, 0x78, 0x6C, 0x78, 0x5F, 0xAC, 0xEC, 0x7E, 0xC0, 0x11, 0x26, 0x9D, 0x4E, 0x47, 0xB3, 0x64, 0xC4, 0xA5 }; @@ -78,12 +78,12 @@ bool GetOtp0x90(void* otp0x90, u32 len) cbc_encrypt(otp0x90, otp0x90, len / 0x10, AES_CNT_TITLEKEY_ENCRYPT_MODE, otp_iv); return true; } - + return false; } bool InitNandCrypto(bool init_full) -{ +{ // part #0: KeyX / KeyY for secret sector 0x96 if (IS_UNLOCKED) { // if OTP is unlocked // see: https://www.3dbrew.org/wiki/OTP_Registers @@ -95,11 +95,11 @@ bool InitNandCrypto(bool init_full) if (GetOtp0x90(otp0x90, 0x90)) sha_quick(OtpSha256, otp0x90, 0x90, SHA256_MODE); } - + // part #1: Get NAND CID, set up TWL/CTR counter u32 NandCid[4]; u8 shasum[32]; - + sdmmc_sdcard_init(); sdmmc_get_cid(1, NandCid); sha_quick(shasum, (u8*) NandCid, 16, SHA256_MODE); @@ -107,7 +107,7 @@ bool InitNandCrypto(bool init_full) sha_quick(shasum, (u8*) NandCid, 16, SHA1_MODE); for(u32 i = 0; i < 16; i++) // little endian and reversed order TwlNandCtr[i] = shasum[15-i]; - + // part #2: TWL KEY (if not already set up) // see: https://www.3dbrew.org/wiki/Memory_layout#ARM9_ITCM if (GetNandPartitionInfo(NULL, NP_TYPE_FAT, NP_SUBTYPE_TWL, 0, NAND_SYSNAND) != 0) { @@ -118,11 +118,11 @@ bool InitNandCrypto(bool init_full) u64 ALIGN(32) otp0x10[2]; if (GetOtp0x90(otp0x10, 0x10)) TwlCustId = *otp0x10; } - + if (TwlCustId) { // give up if TwlCustId not found u32 ALIGN(32) TwlKey0x03Y[4]; u32 ALIGN(32) TwlKey0x03X[4]; - + if (IS_DEVKIT) { TwlKey0x03X[1] = 0xEE7A4B1E; TwlKey0x03X[2] = 0xAF42C08B; @@ -132,20 +132,20 @@ bool InitNandCrypto(bool init_full) TwlKey0x03X[2] = *(vu32*)0x01FFD3AC; // "ENDO" memcpy(TwlKey0x03Y, (u8*) 0x01FFD3C8, 16); } - + TwlKey0x03X[0] = (u32) (TwlCustId>>0); TwlKey0x03X[3] = (u32) (TwlCustId>>32); TwlKey0x03Y[3] = 0xE1A00005; - + setup_aeskeyX(0x03, TwlKey0x03X); setup_aeskeyY(0x03, TwlKey0x03Y); use_aeskey(0x03); - + if (init_full) { // full init vu32 *RegKey0x01X = ®_AESKEY0123[((0x30u * 0x01) + 0x10u)/4u]; RegKey0x01X[2] = (u32) (TwlCustId>>32); RegKey0x01X[3] = (u32) (TwlCustId>>0); - + setup_aeskeyX(0x02, (u8*)0x01FFD398); if (IS_DEVKIT) { u32 ALIGN(32) TwlKey0x02Y[4]; @@ -153,24 +153,24 @@ bool InitNandCrypto(bool init_full) setup_aeskeyY(0x02, TwlKey0x02Y); } else setup_aeskeyY(0x02, (u8*)0x01FFD220); use_aeskey(0x02); - + if (IS_UNLOCKED) (*(vu64*)0x10012100) = TwlCustId; } } } - + // part #3: CTRNAND N3DS KEY (if not set up) if (GetNandPartitionInfo(NULL, NP_TYPE_FAT, NP_SUBTYPE_CTR, 0, NAND_SYSNAND) != 0) LoadKeyFromFile(slot0x05KeyY, 0x05, 'Y', NULL); - + // part #4: AGBSAVE CMAC KEY (set up on unlocked systems) if (init_full && IS_UNLOCKED) LoadKeyFromFile(NULL, 0x24, 'Y', NULL); - + // part #5: FULL INIT if (init_full) InitKeyDb(NULL); - + return true; } @@ -179,11 +179,11 @@ bool CheckSlot0x05Crypto(void) // step #1 - check the slot0x05KeyY SHA-256 if (sha_cmp(slot0x05KeyY_sha256, slot0x05KeyY, 16, SHA256_MODE) == 0) return true; - + // step #2 - check actual presence of CTRNAND FAT if (GetNandPartitionInfo(NULL, NP_TYPE_STD, NP_SUBTYPE_CTR_N, 0, NAND_SYSNAND) == 0) return true; - + // failed if we arrive here return false; } @@ -206,14 +206,14 @@ bool CheckGenuineNandNcsd(void) }; u8 ALIGN(4) gen_n3ds_hash[0x20] = { 0x49, 0xB7, 0x4A, 0xF1, 0xFD, 0xB7, 0xCF, 0x5B, 0x76, 0x8F, 0xA2, 0x94, 0x0D, 0xB2, 0xB3, 0xE2, - 0xA4, 0xBD, 0x25, 0x03, 0x06, 0x03, 0x47, 0x0B, 0x24, 0x5A, 0x86, 0x6A, 0x43, 0x60, 0xBC, 0x84, + 0xA4, 0xBD, 0x25, 0x03, 0x06, 0x03, 0x47, 0x0B, 0x24, 0x5A, 0x86, 0x6A, 0x43, 0x60, 0xBC, 0x84, }; u8 ALIGN(4) gen_hdr[0x100]; if ((ReadNandBytes(gen_hdr, 0x100, 0x100, 0xFF, NAND_SYSNAND) != 0) || (ReadNandBytes(gen_hdr + 0xBE, 0x1BE, 0x42, 0x03, NAND_SYSNAND) != 0)) return false; - + return (sha_cmp((IS_O3DS) ? gen_o3ds_hash : gen_n3ds_hash, gen_hdr, 0x100, SHA256_MODE) == 0); } @@ -226,7 +226,7 @@ void CryptNand(void* buffer, u32 sector, u32 count, u32 keyslot) // copy NAND CTR and increment it memcpy(ctr, (keyslot != 0x03) ? CtrNandCtr : TwlNandCtr, 16); // hacky again add_ctr(ctr, sector * (0x200 / 0x10)); - + // decrypt the data use_aeskey(keyslot); ctr_decrypt((void*) buffer, (void*) buffer, blocks, mode, ctr); @@ -235,11 +235,11 @@ void CryptNand(void* buffer, u32 sector, u32 count, u32 keyslot) void CryptSector0x96(void* buffer, bool encrypt) { u32 mode = encrypt ? AES_CNT_ECB_ENCRYPT_MODE : AES_CNT_ECB_DECRYPT_MODE; - + // setup the key setup_aeskeyX(0x11, OtpSha256); setup_aeskeyY(0x11, OtpSha256 + 16); - + // decrypt the sector use_aeskey(0x11); ecb_decrypt((void*) buffer, (void*) buffer, 0x200 / AES_BLOCK_SIZE, mode); @@ -247,7 +247,7 @@ void CryptSector0x96(void* buffer, bool encrypt) int ReadNandBytes(void* buffer, u64 offset, u64 count, u32 keyslot, u32 nand_src) { - if (!(offset % 0x200) && !(count % 0x200)) { // aligned data -> simple case + if (!(offset % 0x200) && !(count % 0x200)) { // aligned data -> simple case // simple wrapper function for ReadNandSectors(...) return ReadNandSectors(buffer, offset / 0x200, count / 0x200, keyslot, nand_src); } else { // misaligned data -> -___- @@ -280,7 +280,7 @@ int ReadNandBytes(void* buffer, u64 offset, u64 count, u32 keyslot, u32 nand_src int WriteNandBytes(const void* buffer, u64 offset, u64 count, u32 keyslot, u32 nand_dst) { - if (!(offset % 0x200) && !(count % 0x200)) { // aligned data -> simple case + if (!(offset % 0x200) && !(count % 0x200)) { // aligned data -> simple case // simple wrapper function for WriteNandSectors(...) return WriteNandSectors(buffer, offset / 0x200, count / 0x200, keyslot, nand_dst); } else { // misaligned data -> -___- @@ -316,7 +316,7 @@ int WriteNandBytes(const void* buffer, u64 offset, u64 count, u32 keyslot, u32 n } int ReadNandSectors(void* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_src) -{ +{ u8* buffer8 = (u8*) buffer; if (!count) return 0; // <--- just to be safe if (nand_src == NAND_EMUNAND) { // EmuNAND @@ -335,7 +335,7 @@ int ReadNandSectors(void* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_s if (errorcode) return errorcode; } else if (nand_src == NAND_SYSNAND) { // SysNAND int errorcode = sdmmc_nand_readsectors(sector, count, buffer8); - if (errorcode) return errorcode; + if (errorcode) return errorcode; } else if (nand_src == NAND_ZERONAND) { // zero NAND (good for XORpads) memset(buffer8, 0, count * 0x200); } else { @@ -343,7 +343,7 @@ int ReadNandSectors(void* buffer, u32 sector, u32 count, u32 keyslot, u32 nand_s } if ((keyslot == 0x11) && (sector == SECTOR_SECRET)) CryptSector0x96(buffer8, false); else if (keyslot < 0x40) CryptNand(buffer8, sector, count, keyslot); - + return 0; } @@ -353,7 +353,7 @@ int WriteNandSectors(const void* buffer, u32 sector, u32 count, u32 keyslot, u32 void* nand_buffer = (void*) malloc(min(STD_BUFFER_SIZE, count * 0x200)); if (!nand_buffer) return -1; int errorcode = 0; - + for (u32 s = 0; s < count; s += (STD_BUFFER_SIZE / 0x200)) { u32 pcount = min((STD_BUFFER_SIZE/0x200), (count - s)); memcpy(nand_buffer, ((u8*) buffer) + (s*0x200), pcount * 0x200); @@ -372,7 +372,7 @@ int WriteNandSectors(const void* buffer, u32 sector, u32 count, u32 keyslot, u32 errorcode = -1; } } - + free(nand_buffer); return errorcode; } @@ -390,7 +390,7 @@ u32 ValidateNandNcsdHeader(NandNcsdHeader* header) if ((memcmp(header->magic, "NCSD", 4) != 0) || // check magic number (memcmp(header->partitions_fs_type, zeroes, 8) == 0) || header->mediaId) // prevent detection of cart NCSD images return 1; - + u32 data_units = 0; u32 firm_count = 0; for (u32 i = 0; i < 8; i++) { @@ -406,7 +406,7 @@ u32 ValidateNandNcsdHeader(NandNcsdHeader* header) } if (data_units > header->size) return 1; if (!firm_count) return 1; // at least one firm is required - + return 0; } @@ -417,7 +417,7 @@ u32 GetNandNcsdMinSizeSectors(NandNcsdHeader* ncsd) u32 prt_end = ncsd->partitions[prt_idx].offset + ncsd->partitions[prt_idx].size; if (prt_end > nand_minsize) nand_minsize = prt_end; } - + return nand_minsize; } @@ -426,7 +426,7 @@ u32 GetNandMinSizeSectors(u32 nand_src) NandNcsdHeader ncsd; if ((ReadNandSectors((u8*) &ncsd, 0, 1, 0xFF, nand_src) != 0) || (ValidateNandNcsdHeader(&ncsd) != 0)) return 0; - + return GetNandNcsdMinSizeSectors(&ncsd); } @@ -434,7 +434,7 @@ u32 GetNandSizeSectors(u32 nand_src) { u32 sysnand_sectors = getMMCDevice(0)->total_size; if (nand_src == NAND_SYSNAND) return sysnand_sectors; // for SysNAND - + u32 min_sectors = GetNandMinSizeSectors(nand_src); if (nand_src == NAND_EMUNAND) { // for EmuNAND u32 partition_offset = GetPartitionOffsetSector("0:"); @@ -447,7 +447,7 @@ u32 GetNandSizeSectors(u32 nand_src) u32 img_sectors = (GetMountState() & IMG_NAND) ? GetMountSize() / 0x200 : 0; return (img_sectors >= min_sectors) ? img_sectors : 0; } - + return 0; } @@ -456,14 +456,14 @@ u32 GetNandNcsdPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 // safety / set keyslot if ((type == NP_TYPE_FAT) || (type > NP_TYPE_BONUS) || (subtype > NP_SUBTYPE_CTR_N)) return 1; info->keyslot = np_keyslots[type][subtype]; - + // full (minimum) NAND "partition" if (type == NP_TYPE_NONE) { info->sector = 0x00; info->count = GetNandNcsdMinSizeSectors(ncsd); return 0; } - + // special, custom partition types, not in NCSD if (type >= NP_TYPE_NCSD) { if (type == NP_TYPE_NCSD) { @@ -484,7 +484,7 @@ u32 GetNandNcsdPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 } else return 1; return 0; } - + u32 prt_idx = 8; for (prt_idx = 0; prt_idx < 8; prt_idx++) { if ((ncsd->partitions_fs_type[prt_idx] != type) || @@ -492,11 +492,11 @@ u32 GetNandNcsdPartitionInfo(NandPartitionInfo* info, u32 type, u32 subtype, u32 if (index == 0) break; index--; } - + if (prt_idx >= 8) return 1; // not found info->sector = ncsd->partitions[prt_idx].offset; info->count = ncsd->partitions[prt_idx].size; - + return 0; } @@ -546,7 +546,7 @@ u32 AutoEmuNandBase(bool reset) if (!reset) { u32 last_valid = emunand_base_sector; u32 emunand_min_sectors = GetNandMinSizeSectors(NAND_EMUNAND); - + // legacy type multiNAND u32 legacy_sectors = (getMMCDevice(0)->total_size > 0x200000) ? 0x400000 : 0x200000; emunand_base_sector += legacy_sectors - (emunand_base_sector % legacy_sectors); @@ -555,7 +555,7 @@ u32 AutoEmuNandBase(bool reset) emunand_base_sector++; if (GetNandSizeSectors(NAND_EMUNAND) && (GetNandPartitionInfo(NULL, NP_TYPE_NCSD, NP_SUBTYPE_CTR, 0, NAND_EMUNAND) == 0)) return emunand_base_sector; // RedNAND type EmuNAND - + // compact type multiNAND if (emunand_min_sectors && (last_valid % 0x2000 <= 1)) { u32 compact_sectors = align(emunand_min_sectors + 1, 0x2000); @@ -564,7 +564,7 @@ u32 AutoEmuNandBase(bool reset) return emunand_base_sector; } } - + emunand_base_sector = 0x000001; // RedNAND type EmuNAND, default if (GetNandPartitionInfo(NULL, NP_TYPE_NCSD, NP_SUBTYPE_CTR, 0, NAND_EMUNAND) != 0) { emunand_base_sector = 0x000000; // GW type EmuNAND @@ -573,7 +573,7 @@ u32 AutoEmuNandBase(bool reset) // still nothing found? revert to default (RedNAND offset) emunand_base_sector = 0x000001; } - + return emunand_base_sector; } diff --git a/arm9/source/qrcodegen/qrcodegen.c b/arm9/source/qrcodegen/qrcodegen.c index 59f1056..df3a3c1 100644 --- a/arm9/source/qrcodegen/qrcodegen.c +++ b/arm9/source/qrcodegen/qrcodegen.c @@ -1,9 +1,9 @@ -/* +/* * QR Code generator library (C) - * + * * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to @@ -128,12 +128,12 @@ static const int PENALTY_N4 = 10; // Public function - see documentation comment in header file. bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { - + size_t textLen = strlen(text); if (textLen == 0) return qrcodegen_encodeSegmentsAdvanced(NULL, 0, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); size_t bufLen = qrcodegen_BUFFER_LEN_FOR_VERSION(maxVersion); - + struct qrcodegen_Segment seg; if (qrcodegen_isNumeric(text)) { if (qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, textLen) > bufLen) @@ -156,7 +156,7 @@ bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode seg.data = tempBuffer; } return qrcodegen_encodeSegmentsAdvanced(&seg, 1, ecl, minVersion, maxVersion, mask, boostEcl, tempBuffer, qrcode); - + fail: qrcode[0] = 0; // Set size to invalid value for safety return false; @@ -166,7 +166,7 @@ fail: // Public function - see documentation comment in header file. bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcode[], enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl) { - + struct qrcodegen_Segment seg; seg.mode = qrcodegen_Mode_BYTE; seg.bitLength = calcSegmentBitLength(seg.mode, dataLen); @@ -204,7 +204,7 @@ testable void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_ int dataLen = rawCodewords - blockEccLen * numBlocks; int numShortBlocks = numBlocks - rawCodewords % numBlocks; int shortBlockDataLen = rawCodewords / numBlocks - blockEccLen; - + // Split data into blocks and append ECC after all data uint8_t generator[30]; calcReedSolomonGenerator(blockEccLen, generator); @@ -216,7 +216,7 @@ testable void appendErrorCorrection(uint8_t data[], int version, enum qrcodegen_ j += blockEccLen; k += blockLen; } - + // Interleave (not concatenate) the bytes from every block into a single sequence for (int i = 0, k = 0; i < numBlocks; i++) { for (int j = 0, l = i; j < shortBlockDataLen; j++, k++, l += numBlocks) @@ -268,7 +268,7 @@ testable void calcReedSolomonGenerator(int degree, uint8_t result[]) { assert(1 <= degree && degree <= 30); memset(result, 0, degree * sizeof(result[0])); result[degree - 1] = 1; - + // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}), // drop the highest term, and store the rest of the coefficients in order of descending powers. // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D). @@ -289,7 +289,7 @@ testable void calcReedSolomonGenerator(int degree, uint8_t result[]) { // polynomials are in big endian and the generator has an implicit leading 1 term, storing the result in result[0 : degree]. testable void calcReedSolomonRemainder(const uint8_t data[], int dataLen, const uint8_t generator[], int degree, uint8_t result[]) { - + // Perform polynomial division assert(1 <= degree && degree <= 30); memset(result, 0, degree * sizeof(result[0])); @@ -326,16 +326,16 @@ testable void initializeFunctionModules(int version, uint8_t qrcode[]) { int qrsize = version * 4 + 17; memset(qrcode, 0, ((qrsize * qrsize + 7) / 8 + 1) * sizeof(qrcode[0])); qrcode[0] = (uint8_t)qrsize; - + // Fill horizontal and vertical timing patterns fillRectangle(6, 0, 1, qrsize, qrcode); fillRectangle(0, 6, qrsize, 1, qrcode); - + // Fill 3 finder patterns (all corners except bottom right) and format bits fillRectangle(0, 0, 9, 9, qrcode); fillRectangle(qrsize - 8, 0, 8, 9, qrcode); fillRectangle(0, qrsize - 8, 9, 8, qrcode); - + // Fill numerous alignment patterns uint8_t alignPatPos[7] = {0}; int numAlign = getAlignmentPatternPositions(version, alignPatPos); @@ -347,7 +347,7 @@ testable void initializeFunctionModules(int version, uint8_t qrcode[]) { fillRectangle(alignPatPos[i] - 2, alignPatPos[j] - 2, 5, 5, qrcode); } } - + // Fill version blocks if (version >= 7) { fillRectangle(qrsize - 11, 0, 3, 6, qrcode); @@ -366,7 +366,7 @@ static void drawWhiteFunctionModules(uint8_t qrcode[], int version) { setModule(qrcode, 6, i, false); setModule(qrcode, i, 6, false); } - + // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules) for (int i = -4; i <= 4; i++) { for (int j = -4; j <= 4; j++) { @@ -380,7 +380,7 @@ static void drawWhiteFunctionModules(uint8_t qrcode[], int version) { } } } - + // Draw numerous alignment patterns uint8_t alignPatPos[7] = {0}; int numAlign = getAlignmentPatternPositions(version, alignPatPos); @@ -396,7 +396,7 @@ static void drawWhiteFunctionModules(uint8_t qrcode[], int version) { } } } - + // Draw version blocks if (version >= 7) { // Calculate error correction code and pack bits @@ -405,7 +405,7 @@ static void drawWhiteFunctionModules(uint8_t qrcode[], int version) { rem = (rem << 1) ^ ((rem >> 11) * 0x1F25); long data = (long)version << 12 | rem; // uint18 assert(data >> 18 == 0); - + // Draw two copies for (int i = 0; i < 6; i++) { for (int j = 0; j < 3; j++) { @@ -440,7 +440,7 @@ static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uin data = data << 10 | rem; data ^= 0x5412; // uint15 assert(data >> 15 == 0); - + // Draw first copy for (int i = 0; i <= 5; i++) setModule(qrcode, 8, i, ((data >> i) & 1) != 0); @@ -449,7 +449,7 @@ static void drawFormatBits(enum qrcodegen_Ecc ecl, enum qrcodegen_Mask mask, uin setModule(qrcode, 7, 8, ((data >> 8) & 1) != 0); for (int i = 9; i < 15; i++) setModule(qrcode, 14 - i, 8, ((data >> i) & 1) != 0); - + // Draw second copy int qrsize = qrcodegen_getSize(qrcode); for (int i = 0; i <= 7; i++) @@ -554,7 +554,7 @@ static void applyMask(const uint8_t functionModules[], uint8_t qrcode[], enum qr static long getPenaltyScore(const uint8_t qrcode[]) { int qrsize = qrcodegen_getSize(qrcode); long result = 0; - + // Adjacent modules in row having same color for (int y = 0; y < qrsize; y++) { bool colorX; @@ -587,7 +587,7 @@ static long getPenaltyScore(const uint8_t qrcode[]) { } } } - + // 2*2 blocks of modules having same color for (int y = 0; y < qrsize - 1; y++) { for (int x = 0; x < qrsize - 1; x++) { @@ -598,7 +598,7 @@ static long getPenaltyScore(const uint8_t qrcode[]) { result += PENALTY_N2; } } - + // Finder-like pattern in rows for (int y = 0; y < qrsize; y++) { for (int x = 0, bits = 0; x < qrsize; x++) { @@ -615,7 +615,7 @@ static long getPenaltyScore(const uint8_t qrcode[]) { result += PENALTY_N3; } } - + // Balance of black and white modules int black = 0; for (int y = 0; y < qrsize; y++) { @@ -734,7 +734,7 @@ testable int calcSegmentBitLength(enum qrcodegen_Mode mode, size_t numChars) { if (numChars > (unsigned int)LIMIT) return -1; int n = (int)numChars; - + int result = -2; if (mode == qrcodegen_Mode_NUMERIC) { // n * 3 + ceil(n / 3) @@ -798,7 +798,7 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] if (bitLen > 0) memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); result.bitLength = 0; - + unsigned int accumData = 0; int accumCount = 0; for (; *digits != '\0'; digits++) { @@ -832,7 +832,7 @@ struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t bu if (bitLen > 0) memset(buf, 0, ((size_t)bitLen + 7) / 8 * sizeof(buf[0])); result.bitLength = 0; - + unsigned int accumData = 0; int accumCount = 0; for (; *text != '\0'; text++) { @@ -893,7 +893,7 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz assert(segs != NULL || len == 0); assert(qrcodegen_VERSION_MIN <= minVersion && minVersion <= maxVersion && maxVersion <= qrcodegen_VERSION_MAX); // assert(0 <= (int)ecl && (int)ecl <= 3 && -1 <= (int)mask && (int)mask <= 7); - + // Find the minimal version number to use int version, dataUsedBits; for (version = minVersion; ; version++) { @@ -907,13 +907,13 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz } } assert(dataUsedBits != -1); - + // Increase the error correction level while the data still fits in the current version number for (int i = (int)qrcodegen_Ecc_MEDIUM; i <= (int)qrcodegen_Ecc_HIGH; i++) { if (boostEcl && dataUsedBits <= getNumDataCodewords(version, (enum qrcodegen_Ecc)i) * 8) ecl = (enum qrcodegen_Ecc)i; } - + // Create the data bit string by concatenating all segments int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; memset(qrcode, 0, qrcodegen_BUFFER_LEN_FOR_VERSION(version) * sizeof(qrcode[0])); @@ -934,26 +934,26 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz for (int j = 0; j < seg->bitLength; j++) appendBitsToBuffer((seg->data[j >> 3] >> (7 - (j & 7))) & 1, 1, qrcode, &bitLen); } - + // Add terminator and pad up to a byte if applicable int terminatorBits = dataCapacityBits - bitLen; if (terminatorBits > 4) terminatorBits = 4; appendBitsToBuffer(0, terminatorBits, qrcode, &bitLen); appendBitsToBuffer(0, (8 - bitLen % 8) % 8, qrcode, &bitLen); - + // Pad with alternate bytes until data capacity is reached for (uint8_t padByte = 0xEC; bitLen < dataCapacityBits; padByte ^= 0xEC ^ 0x11) appendBitsToBuffer(padByte, 8, qrcode, &bitLen); assert(bitLen % 8 == 0); - + // Draw function and data codeword modules appendErrorCorrection(qrcode, version, ecl, tempBuffer); initializeFunctionModules(version, qrcode); drawCodewords(tempBuffer, getNumRawDataModules(version) / 8, qrcode); drawWhiteFunctionModules(qrcode, version); initializeFunctionModules(version, tempBuffer); - + // Handle masking if (mask == qrcodegen_Mask_AUTO) { // Automatically choose best mask long minPenalty = LONG_MAX; @@ -1012,7 +1012,7 @@ static int numCharCountBits(enum qrcodegen_Mode mode, int version) { else if (10 <= version && version <= 26) i = 1; else if (27 <= version && version <= 40) i = 2; else assert(false); - + switch (mode) { case qrcodegen_Mode_NUMERIC : { const int temp[] = {10, 12, 14}; return temp[i]; } case qrcodegen_Mode_ALPHANUMERIC: { const int temp[] = { 9, 11, 13}; return temp[i]; } diff --git a/arm9/source/qrcodegen/qrcodegen.h b/arm9/source/qrcodegen/qrcodegen.h index 899feae..b0388a5 100644 --- a/arm9/source/qrcodegen/qrcodegen.h +++ b/arm9/source/qrcodegen/qrcodegen.h @@ -1,9 +1,9 @@ -/* +/* * QR Code generator library (C) - * + * * Copyright (c) Project Nayuki. (MIT License) * https://www.nayuki.io/page/qr-code-generator-library - * + * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to @@ -30,7 +30,7 @@ /*---- Enum and struct types----*/ -/* +/* * The error correction level used in a QR Code symbol. */ enum qrcodegen_Ecc { @@ -41,7 +41,7 @@ enum qrcodegen_Ecc { }; -/* +/* * The mask pattern used in a QR Code symbol. */ enum qrcodegen_Mask { @@ -60,7 +60,7 @@ enum qrcodegen_Mask { }; -/* +/* * The mode field of a segment. */ enum qrcodegen_Mode { @@ -72,7 +72,7 @@ enum qrcodegen_Mode { }; -/* +/* * A segment of user/application data that a QR Code symbol can convey. * Each segment has a mode, a character count, and character/general data that is * already encoded as a sequence of bits. The maximum allowed bit length is 32767, @@ -81,17 +81,17 @@ enum qrcodegen_Mode { struct qrcodegen_Segment { // The mode indicator for this segment. enum qrcodegen_Mode mode; - + // The length of this segment's unencoded data. Always in the range [0, 32767]. // For numeric, alphanumeric, and kanji modes, this measures in Unicode code points. // For byte mode, this measures in bytes (raw binary data, text in UTF-8, or other encodings). // For ECI mode, this is always zero. int numChars; - + // The data bits of this segment, packed in bitwise big endian. // Can be null if the bit length is zero. uint8_t *data; - + // The number of valid data bits used in the buffer. Requires // 0 <= bitLength <= 32767, and bitLength <= (capacity of data array) * 8. int bitLength; @@ -120,7 +120,7 @@ struct qrcodegen_Segment { /*---- Functions to generate QR Codes ----*/ -/* +/* * Encodes the given text string to a QR Code symbol, returning true if encoding succeeded. * If the data is too long to fit in any version in the given range * at the given ECC level, then false is returned. @@ -143,7 +143,7 @@ bool qrcodegen_encodeText(const char *text, uint8_t tempBuffer[], uint8_t qrcode enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); -/* +/* * Encodes the given binary data to a QR Code symbol, returning true if encoding succeeded. * If the data is too long to fit in any version in the given range * at the given ECC level, then false is returned. @@ -165,19 +165,19 @@ bool qrcodegen_encodeBinary(uint8_t dataAndTemp[], size_t dataLen, uint8_t qrcod enum qrcodegen_Ecc ecl, int minVersion, int maxVersion, enum qrcodegen_Mask mask, bool boostEcl); -/* +/* * Tests whether the given string can be encoded as a segment in alphanumeric mode. */ bool qrcodegen_isAlphanumeric(const char *text); -/* +/* * Tests whether the given string can be encoded as a segment in numeric mode. */ bool qrcodegen_isNumeric(const char *text); -/* +/* * Returns the number of bytes (uint8_t) needed for the data buffer of a segment * containing the given number of characters using the given mode. Notes: * - Returns SIZE_MAX on failure, i.e. numChars > INT16_MAX or @@ -191,19 +191,19 @@ bool qrcodegen_isNumeric(const char *text); size_t qrcodegen_calcSegmentBufferSize(enum qrcodegen_Mode mode, size_t numChars); -/* +/* * Returns a segment representing the given binary data encoded in byte mode. */ struct qrcodegen_Segment qrcodegen_makeBytes(const uint8_t data[], size_t len, uint8_t buf[]); -/* +/* * Returns a segment representing the given string of decimal digits encoded in numeric mode. */ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[]); -/* +/* * Returns a segment representing the given text string encoded in alphanumeric mode. * The characters allowed are: 0 to 9, A to Z (uppercase only), space, * dollar, percent, asterisk, plus, hyphen, period, slash, colon. @@ -211,14 +211,14 @@ struct qrcodegen_Segment qrcodegen_makeNumeric(const char *digits, uint8_t buf[] struct qrcodegen_Segment qrcodegen_makeAlphanumeric(const char *text, uint8_t buf[]); -/* +/* * Returns a segment representing an Extended Channel Interpretation * (ECI) designator with the given assignment value. */ struct qrcodegen_Segment qrcodegen_makeEci(long assignVal, uint8_t buf[]); -/* +/* * Renders a QR Code symbol representing the given data segments at the given error correction * level or higher. The smallest possible QR Code version is automatically chosen for the output. * Returns true if QR Code creation succeeded, or false if the data is too long to fit in any version. @@ -233,7 +233,7 @@ bool qrcodegen_encodeSegments(const struct qrcodegen_Segment segs[], size_t len, enum qrcodegen_Ecc ecl, uint8_t tempBuffer[], uint8_t qrcode[]); -/* +/* * Renders a QR Code symbol representing the given data segments with the given encoding parameters. * Returns true if QR Code creation succeeded, or false if the data is too long to fit in the range of versions. * The smallest possible QR Code version within the given range is automatically chosen for the output. @@ -250,7 +250,7 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz /*---- Functions to extract raw data from QR Codes ----*/ -/* +/* * Returns the side length of the given QR Code, assuming that encoding succeeded. * The result is in the range [21, 177]. Note that the length of the array buffer * is related to the side length - every 'uint8_t qrcode[]' must have length at least @@ -259,7 +259,7 @@ bool qrcodegen_encodeSegmentsAdvanced(const struct qrcodegen_Segment segs[], siz int qrcodegen_getSize(const uint8_t qrcode[]); -/* +/* * Returns the color of the module (pixel) at the given coordinates, which is either * false for white or true for black. The top left corner has the coordinates (x=0, y=0). * If the given coordinates are out of bounds, then false (white) is returned. diff --git a/arm9/source/system/memmap.h b/arm9/source/system/memmap.h index 96e278f..ec30ef7 100644 --- a/arm9/source/system/memmap.h +++ b/arm9/source/system/memmap.h @@ -63,7 +63,7 @@ #define __STACK_ABT_LEN 0x10000 #define __STACK_TOP (__STACK_ABT_TOP - __STACK_ABT_LEN) -#define __STACK_LEN 0x7F0000 +#define __STACK_LEN 0x7F0000 #define __HEAP_ADDR (__FCRAM0_ADDR + 0x0001000) #define __HEAP_END (__STACK_TOP - __STACK_LEN) diff --git a/arm9/source/system/spiflash.c b/arm9/source/system/spiflash.c index 6964770..cd83a65 100755 --- a/arm9/source/system/spiflash.c +++ b/arm9/source/system/spiflash.c @@ -20,7 +20,7 @@ bool spiflash_read(u32 offset, u32 size, u8 *buf) ARM_WbDC_Range(ARM_GetSHMEM()->spiBuffer, blksz); PXI_DoCMD(PXI_NVRAM_READ, args, 2); - ARM_InvDC_Range(ARM_GetSHMEM()->spiBuffer, blksz); + ARM_InvDC_Range(ARM_GetSHMEM()->spiBuffer, blksz); ARM_DSB(); memcpy(buf, ARM_GetSHMEM()->spiBuffer, blksz); diff --git a/arm9/source/system/tar.c b/arm9/source/system/tar.c index d580a0a..7b5f63a 100644 --- a/arm9/source/system/tar.c +++ b/arm9/source/system/tar.c @@ -3,38 +3,38 @@ u64 ReadAsciiOctal(char* num, u32 len) { u64 res = 0; - + if ((num[len-1] != '\0') && (num[len-1] != ' ')) return (u64) -1; - + for (u32 i = 0; i < (len-1); i++) { res <<= 3; if ((num[i] >= '0') && (num[i] < '8')) res |= (num[i] - '0'); else return (u64) -1; } - + return res; } u32 ValidateTarHeader(void* tardata, void* tardata_end) { TarHeader* tar = tardata; - + // available space if ((u8*) tardata_end < (u8*) tardata + sizeof(TarHeader)) return 1; - + // filename prefix is not supported here if (*(tar->fname_prefix)) return 1; - + // check filesize u64 fsize_max = ((u8*) tardata_end - (u8*) tardata) - sizeof(TarHeader); if (ReadAsciiOctal(tar->fsize, 12) > fsize_max) return 1; - + // type can only be standard file or dir if (tar->ftype && (tar->ftype != '0') && (tar->ftype != '5')) return 1; - + // checksum u8* data = (u8*) tardata; u64 checksum = 0; @@ -42,18 +42,18 @@ u32 ValidateTarHeader(void* tardata, void* tardata_end) { checksum += ((i < 148) || (i >= 156)) ? data[i] : (u64) ' '; if (checksum != ReadAsciiOctal(tar->checksum, 7)) return 1; - + return 0; } void* GetTarFileInfo(void* tardata, char* fname, u64* fsize, bool* is_dir) { // this assumes a valid TAR header TarHeader* tar = tardata; - + if (fname) snprintf(fname, 101, "%.100s", tar->fname); if (fsize) *fsize = ReadAsciiOctal(tar->fsize, 12); if (is_dir) *is_dir = (tar->ftype == '5'); - + return (void*) (tar + 1); } @@ -62,23 +62,23 @@ void* NextTarEntry(void* tardata, void* tardata_end) { TarHeader* tar = tardata; u8* data = (u8*) tardata; u64 fsize = ReadAsciiOctal(tar->fsize, 12); - + data += sizeof(TarHeader) + align(fsize, 512); if (ValidateTarHeader(data, tardata_end) != 0) return NULL; - + return data; } void* FindTarFileInfo(void* tardata, void* tardata_end, const char* fname, u64* fsize) { while (tardata && (tardata < tardata_end)) { TarHeader* tar = tardata; - + if (ValidateTarHeader(tardata, tardata_end) != 0) break; if ((strncasecmp(tar->fname, fname, 100) == 0) && (!tar->ftype || (tar->ftype == '0'))) return GetTarFileInfo(tardata, NULL, fsize, NULL); tardata = ((u8*) tardata) + sizeof(TarHeader) + align(ReadAsciiOctal(tar->fsize, 12), 512); } - + return NULL; } diff --git a/arm9/source/system/vram0.h b/arm9/source/system/vram0.h index c397bc0..490e11a 100644 --- a/arm9/source/system/vram0.h +++ b/arm9/source/system/vram0.h @@ -31,15 +31,15 @@ #define FirstVTarEntry() \ TARDATA - + #define OffsetVTarEntry(off) \ TARDATA_(off) #define NextVTarEntry(tardata) \ NextTarEntry(tardata, TARDATA_END) - + #define GetVTarFileInfo(tardata, fname, fsize, is_dir) \ GetTarFileInfo(tardata, fname, fsize, is_dir) - + #define FindVTarFileInfo(fname, fsize) \ FindTarFileInfo(TARDATA, TARDATA_END, fname, fsize) diff --git a/arm9/source/utils/ctrtransfer.c b/arm9/source/utils/ctrtransfer.c index 7ac1c91..5258360 100644 --- a/arm9/source/utils/ctrtransfer.c +++ b/arm9/source/utils/ctrtransfer.c @@ -42,7 +42,7 @@ u32 CheckTransferableMbr(void* data) { // strict checks, custom partitions not a u32 TransferCtrNandImage(const char* path_img, const char* drv) { if (!CheckWritePermissions(drv)) return 1; - + // backup current mount path, mount new path char path_store[256] = { 0 }; char* path_bak = NULL; @@ -53,7 +53,7 @@ u32 TransferCtrNandImage(const char* path_img, const char* drv) { InitImgFS(path_bak); return 1; } - + // CTRNAND preparations SecureInfo secnfo_img; SecureInfo secnfo_loc; @@ -62,19 +62,19 @@ u32 TransferCtrNandImage(const char* path_img, const char* drv) { char path_secnfo_c[32]; char path_tickdb[32]; char path_tickdb_bak[32]; - + snprintf(path_secnfo_a, 32, "%s/rw/sys/SecureInfo_A", drv); snprintf(path_secnfo_b, 32, "%s/rw/sys/SecureInfo_B", drv); snprintf(path_secnfo_c, 32, "%s/rw/sys/SecureInfo_C", drv); snprintf(path_tickdb, 32, "%s/dbs/ticket.db", drv); snprintf(path_tickdb_bak, 32, "%s/dbs/ticket.bak", drv); - + // special handling for out of region images (create SecureInfo_C) PathDelete(path_secnfo_c); // not required when transfering back to original region - if (((FileGetData("7:/rw/sys/SecureInfo_A", (u8*) &secnfo_img, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) || + if (((FileGetData("7:/rw/sys/SecureInfo_A", (u8*) &secnfo_img, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) || (FileGetData("7:/rw/sys/SecureInfo_B", (u8*) &secnfo_img, sizeof(SecureInfo), 0) == sizeof(SecureInfo))) && - ((FileGetData(path_secnfo_a, (u8*) &secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) || - (FileGetData(path_secnfo_b, (u8*) &secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo))) && + ((FileGetData(path_secnfo_a, (u8*) &secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo)) || + (FileGetData(path_secnfo_b, (u8*) &secnfo_loc, sizeof(SecureInfo), 0) == sizeof(SecureInfo))) && (secnfo_img.region != secnfo_loc.region)) { secnfo_loc.region = secnfo_img.region; FileSetData(path_secnfo_c, (u8*) &secnfo_loc, sizeof(SecureInfo), 0, true); @@ -95,7 +95,7 @@ u32 TransferCtrNandImage(const char* path_img, const char* drv) { drv, sha256sum[0], sha256sum[1], sha256sum[2], sha256sum[3]); PathDelete(path_asr); } - + // actual transfer - db files / titles static const char* dbnames[] = { "ticket.db", "certs.db", "title.db", "import.db", "tmp_t.db", "tmp_i.db" }; char path_to[32]; @@ -115,7 +115,7 @@ u32 TransferCtrNandImage(const char* path_img, const char* drv) { snprintf(path_from, 32, "7:/title"); PathDelete(path_to); PathCopy(drv, path_from, &flags); - + InitImgFS(path_bak); return 0; } diff --git a/arm9/source/utils/gameutil.c b/arm9/source/utils/gameutil.c index 42a584c..e184639 100644 --- a/arm9/source/utils/gameutil.c +++ b/arm9/source/utils/gameutil.c @@ -11,7 +11,7 @@ #include "aes.h" #include "sha.h" -// use NCCH crypto defines for everything +// use NCCH crypto defines for everything #define CRYPTO_DECRYPT NCCH_NOCRYPTO #define CRYPTO_ENCRYPT NCCH_STDCRYPTO @@ -25,7 +25,7 @@ u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, ncch->flags[7] = (ncch->flags[7] & ~0x21) | 0x04; } if (ValidateNcchHeader(ncch) != 0) return 1; - + if (exthdr) { if (!ncch->size_exthdr) return 1; fvx_lseek(file, offset_ncch + NCCH_EXTHDR_OFFSET); @@ -33,7 +33,7 @@ u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, (DecryptNcch((u8*) exthdr, NCCH_EXTHDR_OFFSET, NCCH_EXTHDR_SIZE, ncch, NULL) != 0)) return 1; } - + if (exefs) { if (!ncch->size_exefs) return 1; u32 offset_exefs = offset_ncch + (ncch->offset_exefs * NCCH_MEDIA_UNIT); @@ -43,17 +43,17 @@ u32 GetNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, (ValidateExeFsHeader(exefs, ncch->size_exefs * NCCH_MEDIA_UNIT) != 0)) return 1; } - + return 0; } u32 CheckNcchHash(u8* expected, FIL* file, u32 size_data, u32 offset_ncch, NcchHeader* ncch, ExeFsHeader* exefs) { u32 offset_data = fvx_tell(file) - offset_ncch; u8 hash[32]; - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) return 1; - + sha_init(SHA256_MODE); for (u32 i = 0; i < size_data; i += STD_BUFFER_SIZE) { u32 read_bytes = min(STD_BUFFER_SIZE, (size_data - i)); @@ -63,15 +63,15 @@ u32 CheckNcchHash(u8* expected, FIL* file, u32 size_data, u32 offset_ncch, NcchH sha_update(buffer, read_bytes); } sha_get(hash); - + free(buffer); - + return (memcmp(hash, expected, 32) == 0) ? 0 : 1; } u32 LoadNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, const char* path, u32 offset) { FIL file; - + // open file, get NCCH header if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; @@ -81,14 +81,14 @@ u32 LoadNcchHeaders(NcchHeader* ncch, NcchExtHeader* exthdr, ExeFsHeader* exefs, return 1; } fvx_close(&file); - + return 0; } u32 LoadNcsdHeader(NcsdHeader* ncsd, const char* path) { FIL file; UINT btr; - + // open file, get NCSD header if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; @@ -99,7 +99,7 @@ u32 LoadNcsdHeader(NcsdHeader* ncsd, const char* path) { return 1; } fvx_close(&file); - + return 0; } @@ -107,10 +107,10 @@ u32 LoadCiaStub(CiaStub* stub, const char* path) { FIL file; UINT btr; CiaInfo info; - + if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - + // first 0x20 byte of CIA header fvx_lseek(&file, 0); if ((fvx_read(&file, stub, 0x20, &btr) != FR_OK) || (btr != 0x20) || @@ -119,14 +119,14 @@ u32 LoadCiaStub(CiaStub* stub, const char* path) { return 1; } GetCiaInfo(&info, &(stub->header)); - + // everything up till content offset fvx_lseek(&file, 0); if ((fvx_read(&file, stub, info.offset_content, &btr) != FR_OK) || (btr != info.offset_content)) { fvx_close(&file); return 1; } - + fvx_close(&file); return 0; } @@ -137,7 +137,7 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3 FIL file; UINT btr; u32 ret = 0; - + // open file, get NCCH, ExeFS header if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; @@ -147,7 +147,7 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3 fvx_close(&file); return 1; } - + // load file from exefs ExeFsFileHeader* exefile = NULL; for (u32 i = 0; i < 10; i++) { @@ -159,7 +159,7 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3 break; } } - + if (exefile) { u32 size_exefile = exefile->size; u32 offset_exefile = (ncch.offset_exefs * NCCH_MEDIA_UNIT) + sizeof(ExeFsHeader) + exefile->offset; @@ -170,7 +170,7 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3 ret = 1; } } else ret = 1; - + if (bytes_read) *bytes_read = btr; fvx_close(&file); return ret; @@ -179,13 +179,13 @@ u32 LoadExeFsFile(void* data, const char* path, u32 offset, const char* name, u3 u32 LoadNcchMeta(CiaMeta* meta, const char* path, u64 offset) { NcchHeader ncch; NcchExtHeader exthdr; - + // get dependencies from exthdr, icon from exeFS if ((LoadNcchHeaders(&ncch, &exthdr, NULL, path, offset) != 0) || (BuildCiaMeta(meta, &exthdr, NULL) != 0) || (LoadExeFsFile(meta->smdh, path, offset, "icon", sizeof(meta->smdh), NULL))) return 1; - + return 0; } @@ -198,7 +198,7 @@ u32 LoadTmdFile(TitleMetaData* tmd, const char* path) { // second part (read full size) if (fvx_qread(path, tmd, 0, TMD_SIZE_N(getbe16(tmd->content_count)), NULL) != FR_OK) return 1; - + return 0; } @@ -213,7 +213,7 @@ u32 LoadCdnTicketFile(Ticket** ticket, const char* path_cnt) { char* ext_cetk = strrchr(++name_cetk, '.'); ext_cetk = (ext_cetk) ? ext_cetk + 1 : name_cetk; snprintf(ext_cetk, 256 - (ext_cetk - path_cetk), "cetk"); - + // load and check ticket TicketMinimum tmp; UINT br; @@ -237,7 +237,7 @@ u32 LoadCdnTicketFile(Ticket** ticket, const char* path_cnt) { u32 GetTmdContentPath(char* path_content, const char* path_tmd) { // get path to TMD first content static const u8 dlc_tid_high[] = { DLC_TID_HIGH }; - + // content path string char* name_content; strncpy(path_content, path_tmd, 256); @@ -245,7 +245,7 @@ u32 GetTmdContentPath(char* path_content, const char* path_tmd) { name_content = strrchr(path_content, '/'); if (!name_content) return 1; // will not happen name_content++; - + // load TMD file TitleMetaData* tmd = (TitleMetaData*) malloc(TMD_SIZE_MAX); TmdContentChunk* chunk = (TmdContentChunk*) (tmd + 1); @@ -256,7 +256,7 @@ u32 GetTmdContentPath(char* path_content, const char* path_tmd) { } snprintf(name_content, 256 - (name_content - path_content), (memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0) ? "00000000/%08lx.app" : "%08lx.app", getbe32(chunk->id)); - + free(tmd); return 0; } @@ -289,13 +289,13 @@ u32 GetTieTmdPath(char* path_tmd, const char* path_tie) { if (tid_high & 0x8000) { if (*drv == '1') *drv = '2'; if (*drv == '4') *drv = '5'; - tid_high = 0x00030000 | (tid_high&0xFF); + tid_high = 0x00030000 | (tid_high&0xFF); } - + // build the path snprintf(path_tmd, 64, "%2.2s/title/%08lX/%08lX/content/%08lx.tmd", drv, tid_high, tid_low, tie.tmd_content_id); - + // done return 0; } @@ -315,9 +315,9 @@ u32 WriteCiaStub(CiaStub* stub, const char* path) { FIL file; UINT btw; CiaInfo info; - + GetCiaInfo(&info, &(stub->header)); - + // everything up till content offset if (fvx_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS) != FR_OK) return 1; @@ -326,7 +326,7 @@ u32 WriteCiaStub(CiaStub* stub, const char* path) { fvx_close(&file); return 1; } - + fvx_close(&file); return 0; } @@ -335,11 +335,11 @@ u32 VerifyTmdContent(const char* path, u64 offset, TmdContentChunk* chunk, const u8 hash[32]; u8 ctr[16]; FIL file; - + u8* expected = chunk->hash; u64 size = getbe64(chunk->size); bool encrypted = getbe16(chunk->type) & 0x1; - + if (!ShowProgress(0, 0, path)) return 1; if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; @@ -348,13 +348,13 @@ u32 VerifyTmdContent(const char* path, u64 offset, TmdContentChunk* chunk, const return 1; } fvx_lseek(&file, offset); - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { fvx_close(&file); return 1; } - + GetTmdCtr(ctr, chunk); sha_init(SHA256_MODE); for (u32 i = 0; i < size; i += STD_BUFFER_SIZE) { @@ -368,7 +368,7 @@ u32 VerifyTmdContent(const char* path, u64 offset, TmdContentChunk* chunk, const sha_get(hash); free(buffer); fvx_close(&file); - + return memcmp(hash, expected, 32); } @@ -379,14 +379,14 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { NcchExtHeader exthdr; ExeFsHeader exefs; FIL file; - + char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - + // open file, get NCCH, ExeFS header if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - + // fetch and check NCCH header fvx_lseek(&file, offset); if (GetNcchHeaders(&ncch, NULL, NULL, &file, cryptofix) != 0) { @@ -394,7 +394,7 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { fvx_close(&file); return 1; } - + // check NCCH size if (!size) size = fvx_size(&file) - offset; if ((fvx_size(&file) < offset) || (size < ncch.size * NCCH_MEDIA_UNIT)) { @@ -402,7 +402,7 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { fvx_close(&file); return 1; } - + // fetch and check ExeFS header fvx_lseek(&file, offset); if (ncch.size_exefs && (GetNcchHeaders(&ncch, NULL, &exefs, &file, cryptofix) != 0)) { @@ -442,29 +442,29 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { fvx_close(&file); return 1; } - + u32 ver_exthdr = 0; u32 ver_exefs = 0; u32 ver_romfs = 0; - + // base hash check for extheader if (ncch.size_exthdr > 0) { fvx_lseek(&file, offset + NCCH_EXTHDR_OFFSET); ver_exthdr = CheckNcchHash(ncch.hash_exthdr, &file, 0x400, offset, &ncch, NULL); } - + // base hash check for exefs if (ncch.size_exefs > 0) { fvx_lseek(&file, offset + (ncch.offset_exefs * NCCH_MEDIA_UNIT)); ver_exefs = CheckNcchHash(ncch.hash_exefs, &file, ncch.size_exefs_hash * NCCH_MEDIA_UNIT, offset, &ncch, &exefs); } - + // base hash check for romfs if (ncch.size_romfs > 0) { fvx_lseek(&file, offset + (ncch.offset_romfs * NCCH_MEDIA_UNIT)); ver_romfs = CheckNcchHash(ncch.hash_romfs, &file, ncch.size_romfs_hash * NCCH_MEDIA_UNIT, offset, &ncch, NULL); } - + // thorough exefs verification (workaround for Process9) if (!ShowProgress(0, 0, path)) return 1; if ((ncch.size_exefs > 0) && (memcmp(exthdr.name, "Process9", 8) != 0)) { @@ -480,14 +480,14 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { // thorough romfs verification if (!ver_romfs && (ncch.size_romfs > 0)) { UINT btr; - + // load ivfc header RomFsIvfcHeader ivfc; fvx_lseek(&file, offset + (ncch.offset_romfs * NCCH_MEDIA_UNIT)); if ((fvx_read(&file, &ivfc, sizeof(RomFsIvfcHeader), &btr) != FR_OK) || (DecryptNcch((u8*) &ivfc, ncch.offset_romfs * NCCH_MEDIA_UNIT, sizeof(RomFsIvfcHeader), &ncch, NULL) != 0) ) ver_romfs = 1; - + // load data u64 lvl1_size = 0; u64 lvl2_size = 0; @@ -531,22 +531,22 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { if (!masterhash || !lvl1_data || !lvl2_data) ver_romfs = 1; // should never happen } - + // actual verification if (!ver_romfs) { // verify lvl1 u32 n_blocks = lvl1_size >> ivfc.log_lvl1; u32 block_log = ivfc.log_lvl1; - for (u32 i = 0; !ver_romfs && (i < n_blocks); i++) + for (u32 i = 0; !ver_romfs && (i < n_blocks); i++) ver_romfs = (u32) sha_cmp(masterhash + (i*0x20), lvl1_data + (i<> ivfc.log_lvl2; block_log = ivfc.log_lvl2; for (u32 i = 0; !ver_romfs && (i < n_blocks); i++) { ver_romfs = sha_cmp(lvl1_data + (i*0x20), lvl2_data + (i<> ivfc.log_lvl3; @@ -563,14 +563,14 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { if (lvl1_data) free(lvl1_data); if (lvl2_data) free(lvl2_data); } - + if (!offset && (ver_exthdr|ver_exefs|ver_romfs)) { // verification summary ShowPrompt(false, "%s\nNCCH verification failed:\nExtHdr/ExeFS/RomFS: %s/%s/%s", pathstr, (!ncch.size_exthdr) ? "-" : (ver_exthdr == 0) ? "ok" : "fail", (!ncch.size_exefs) ? "-" : (ver_exefs == 0) ? "ok" : "fail", (!ncch.size_romfs) ? "-" : (ver_romfs == 0) ? "ok" : "fail"); } - + fvx_close(&file); if (cryptofix) fvx_qwrite(path, &ncch, offset, sizeof(NcchHeader), NULL); return ver_exthdr|ver_exefs|ver_romfs; @@ -578,17 +578,17 @@ u32 VerifyNcchFile(const char* path, u32 offset, u32 size) { u32 VerifyNcsdFile(const char* path) { NcsdHeader ncsd; - + // path string char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - + // load NCSD header if (LoadNcsdHeader(&ncsd, path) != 0) { ShowPrompt(false, "%s\nError: Not a NCSD file", pathstr); return 1; } - + // validate NCSD contents for (u32 i = 0; i < 8; i++) { NcchPartition* partition = ncsd.partitions + i; @@ -601,7 +601,7 @@ u32 VerifyNcsdFile(const char* path) { return 1; } } - + return 0; } @@ -609,13 +609,13 @@ u32 VerifyCiaFile(const char* path) { CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); CiaInfo info; u8 titlekey[16]; - + if (!cia) return 1; - + // path string char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - + // load CIA stub if ((LoadCiaStub(cia, path) != 0) || (GetCiaInfo(&info, &(cia->header)) != 0) || @@ -631,7 +631,7 @@ u32 VerifyCiaFile(const char* path) { free(cia); return 1; } - + // verify contents u32 content_count = getbe16(cia->tmd.content_count); u64 next_offset = info.offset_content; @@ -648,18 +648,18 @@ u32 VerifyCiaFile(const char* path) { } next_offset += getbe64(chunk->size); } - + free(cia); return 0; } u32 VerifyTmdFile(const char* path, bool cdn) { static const u8 dlc_tid_high[] = { DLC_TID_HIGH }; - + // path string char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - + // content path string char path_content[256]; char* name_content; @@ -668,7 +668,7 @@ u32 VerifyTmdFile(const char* path, bool cdn) { name_content = strrchr(path_content, '/'); if (!name_content) return 1; // will not happen name_content++; - + // load TMD file TitleMetaData* tmd = (TitleMetaData*) malloc(TMD_SIZE_MAX); TmdContentChunk* content_list = (TmdContentChunk*) (tmd + 1); @@ -677,7 +677,7 @@ u32 VerifyTmdFile(const char* path, bool cdn) { free(tmd); return 1; } - + u8 titlekey[0x10] = { 0xFF }; if (cdn) { // load / build ticket (for titlekey / CDN only) Ticket* ticket = NULL; @@ -693,7 +693,7 @@ u32 VerifyTmdFile(const char* path, bool cdn) { } free(ticket); } - + // verify contents u32 content_count = getbe16(tmd->content_count); bool dlc = !cdn && (memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0); @@ -709,7 +709,7 @@ u32 VerifyTmdFile(const char* path, bool cdn) { return 1; } } - + free(tmd); return 0; } @@ -728,10 +728,10 @@ u32 VerifyTieFile(const char* path) { u32 VerifyFirmFile(const char* path) { char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - + void* firm_buffer = (void*) malloc(FIRM_MAX_SIZE); if (!firm_buffer) return 1; - + // load the whole FIRM into memory u32 firm_size = fvx_qsize(path); if ((firm_size > FIRM_MAX_SIZE) || (fvx_qread(path, firm_buffer, 0, firm_size, NULL) != FR_OK) || @@ -739,12 +739,12 @@ u32 VerifyFirmFile(const char* path) { free(firm_buffer); return 1; } - + // hash verify all available sections FirmHeader header; memcpy(&header, firm_buffer, sizeof(FirmHeader)); for (u32 i = 0; i < 4; i++) { - FirmSectionHeader* sct = header.sections + i; + FirmSectionHeader* sct = header.sections + i; void* section = ((u8*) firm_buffer) + sct->offset; if (!(sct->size)) continue; if (sha_cmp(sct->hash, section, sct->size, SHA256_MODE) != 0) { @@ -753,7 +753,7 @@ u32 VerifyFirmFile(const char* path) { return 1; } } - + // no arm11 / arm9 entrypoints? if (!header.entry_arm9) { ShowPrompt(false, "%s\nARM9 entrypoint is missing", pathstr); @@ -762,7 +762,7 @@ u32 VerifyFirmFile(const char* path) { } else if (!header.entry_arm11) { ShowPrompt(false, "%s\nWarning: ARM11 entrypoint is missing", pathstr); } - + free(firm_buffer); return 0; } @@ -773,11 +773,11 @@ u32 VerifyBossFile(const char* path) { bool encrypted = false; FIL file; UINT btr; - + char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - - // read file header + + // read file header if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; fvx_lseek(&file, 0); @@ -787,46 +787,46 @@ u32 VerifyBossFile(const char* path) { fvx_close(&file); return 1; } - + // get / check size payload_size = getbe32(boss.filesize) - sizeof(BossHeader); if (!payload_size) { fvx_close(&file); return 1; } - + // check if encrypted, decrypt if required encrypted = (CheckBossEncrypted(&boss) == 0); if (encrypted) CryptBoss((void*) &boss, 0, sizeof(BossHeader), &boss); - + // set up a buffer u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { fvx_close(&file); return 1; } - + // actual hash calculation & compare u8 hash[32]; sha_init(SHA256_MODE); - + GetBossPayloadHashHeader(buffer, &boss); u32 read_bytes = min((STD_BUFFER_SIZE - BOSS_SIZE_PAYLOAD_HEADER), payload_size); fvx_read(&file, buffer + BOSS_SIZE_PAYLOAD_HEADER, read_bytes, &btr); if (encrypted) CryptBoss(buffer + BOSS_SIZE_PAYLOAD_HEADER, sizeof(BossHeader), read_bytes, &boss); sha_update(buffer, read_bytes + BOSS_SIZE_PAYLOAD_HEADER); - + for (u32 i = read_bytes; i < payload_size; i += STD_BUFFER_SIZE) { read_bytes = min(STD_BUFFER_SIZE, (payload_size - i)); fvx_read(&file, buffer, read_bytes, &btr); if (encrypted) CryptBoss(buffer, sizeof(BossHeader) + i, read_bytes, &boss); sha_update(buffer, read_bytes); } - + sha_get(hash); fvx_close(&file); free(buffer); - + if (memcmp(hash, boss.hash_payload, 0x20) != 0) { if (ShowPrompt(true, "%s\nBOSS payload hash mismatch.\n \nTry to fix it?", pathstr)) { // fix hash, reencrypt BOSS header if required, write to file @@ -837,7 +837,7 @@ u32 VerifyBossFile(const char* path) { return 1; } else return 1; } - + return 0; } @@ -869,11 +869,11 @@ u32 CheckEncryptedNcchFile(const char* path, u32 offset) { u32 CheckEncryptedNcsdFile(const char* path) { NcsdHeader ncsd; - + // load NCSD header if (LoadNcsdHeader(&ncsd, path) != 0) return 1; - + // check for encryption in NCSD contents for (u32 i = 0; i < 8; i++) { NcchPartition* partition = ncsd.partitions + i; @@ -882,23 +882,23 @@ u32 CheckEncryptedNcsdFile(const char* path) { if (CheckEncryptedNcchFile(path, offset) == 0) return 0; } - + return 1; } u32 CheckEncryptedCiaFile(const char* path) { CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); CiaInfo info; - + if (!cia) return 1; - + // load CIA stub if ((LoadCiaStub(cia, path) != 0) || (GetCiaInfo(&info, &(cia->header)) != 0)) { free(cia); return 1; } - + // check for encryption in CIA contents u32 content_count = getbe16(cia->tmd.content_count); u64 next_offset = info.offset_content; @@ -910,7 +910,7 @@ u32 CheckEncryptedCiaFile(const char* path) { } next_offset += getbe64(chunk->size); } - + free(cia); return 1; } @@ -919,7 +919,7 @@ u32 CheckEncryptedFirmFile(const char* path) { FirmHeader header; FIL file; UINT btr; - + // open file, get FIRM header if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; @@ -929,7 +929,7 @@ u32 CheckEncryptedFirmFile(const char* path) { fvx_close(&file); return 1; } - + // check ARM9 binary for ARM9 loader FirmSectionHeader* arm9s = FindFirmArm9Section(&header); if (arm9s) { @@ -941,7 +941,7 @@ u32 CheckEncryptedFirmFile(const char* path) { return 0; } } - + fvx_close(&file); return 1; } @@ -979,15 +979,15 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 FIL* ofp = &ofile; FIL* dfp = (inplace) ? &ofile : &dfile; FSIZE_t fsize; - + // FIRM encryption is not possible (yet) if ((mode & SYS_FIRM) && (crypto != CRYPTO_DECRYPT)) return 1; - + // check for BOSS crypto bool crypt_boss = ((mode & GAME_BOSS) && (CheckEncryptedBossFile(orig) == 0)); crypt_boss = ((mode & GAME_BOSS) && (crypt_boss == (crypto == CRYPTO_DECRYPT))); - + // open file(s) if (inplace) { if (fvx_open(ofp, orig, FA_READ | FA_WRITE | FA_OPEN_EXISTING) != FR_OK) @@ -1003,11 +1003,11 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 fvx_lseek(ofp, offset); fvx_lseek(dfp, offset); } - + fsize = fvx_size(ofp); // for progress bar if (fsize < offset) return 1; if (!size) size = fsize - offset; - + // ensure free space in destination if (!inplace) { if ((fvx_lseek(dfp, offset + size) != FR_OK) || @@ -1018,7 +1018,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 return 1; } } - + // set up buffer u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { @@ -1026,7 +1026,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 fvx_close(dfp); return 1; } - + u32 ret = 0; if (!ShowProgress(offset, fsize, dest)) ret = 1; if (mode & (GAME_NCCH|GAME_NCSD|GAME_BOSS|SYS_FIRM|GAME_NDS)) { // for NCCH / NCSD / BOSS / FIRM files @@ -1049,7 +1049,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 bool ncch_crypto; // find out by decrypting the NCCH header UINT bytes_read, bytes_written; u8 ctr[16]; - + NcchHeader* ncch = (NcchHeader*) (void*) buffer; GetTmdCtr(ctr, chunk); // NCCH crypto? if (fvx_read(ofp, buffer, sizeof(NcchHeader), &bytes_read) != FR_OK) ret = 1; @@ -1057,7 +1057,7 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 ncch_crypto = ((ValidateNcchHeader(ncch) == 0) && (NCCH_ENCRYPTED(ncch) || !(crypto & NCCH_NOCRYPTO))); if (ncch_crypto && (SetupNcchCrypto(ncch, crypto) != 0)) ret = 1; - + GetTmdCtr(ctr, chunk); fvx_lseek(ofp, offset); sha_init(SHA256_MODE); @@ -1075,11 +1075,11 @@ u32 CryptNcchNcsdBossFirmFile(const char* orig, const char* dest, u32 mode, u16 sha_get(chunk->hash); chunk->type[1] &= ~0x01; } - + fvx_close(ofp); if (!inplace) fvx_close(dfp); if (buffer) free(buffer); - + return ret; } @@ -1087,13 +1087,13 @@ u32 CryptCiaFile(const char* orig, const char* dest, u16 crypto) { bool inplace = (strncmp(orig, dest, 256) == 0); CiaInfo info; u8 titlekey[16]; - + // start operation if (!ShowProgress(0, 0, orig)) return 1; - + // if not inplace: clear destination if (!inplace) f_unlink(dest); - + // load CIA stub from origin CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); if (!cia) return 1; @@ -1103,7 +1103,7 @@ u32 CryptCiaFile(const char* orig, const char* dest, u16 crypto) { free(cia); return 1; } - + // decrypt CIA contents u32 content_count = getbe16(cia->tmd.content_count); u64 next_offset = info.offset_content; @@ -1119,7 +1119,7 @@ u32 CryptCiaFile(const char* orig, const char* dest, u16 crypto) { } next_offset += size; } - + // if not inplace: take over CIA metadata if (!inplace && (info.size_meta == CIA_META_SIZE)) { CiaMeta* meta = (CiaMeta*) (void*) (cia + 1); @@ -1129,13 +1129,13 @@ u32 CryptCiaFile(const char* orig, const char* dest, u16 crypto) { return 1; } } - + // fix TMD hashes, write CIA stub to destination if ((FixTmdHashes(&(cia->tmd)) != 0) || (WriteCiaStub(cia, dest) != 0)) { free(cia); return 1; } - + free(cia); return 0; } @@ -1144,7 +1144,7 @@ u32 DecryptFirmFile(const char* orig, const char* dest) { static const u8 dec_magic[] = { 'D', 'E', 'C', '\0' }; // insert to decrypted firms void* firm_buffer = (void*) malloc(FIRM_MAX_SIZE); if (!firm_buffer) return 1; - + // load the whole FIRM into memory & decrypt it ShowProgress(0, 2, dest); u32 firm_size = fvx_qsize(orig); @@ -1153,18 +1153,18 @@ u32 DecryptFirmFile(const char* orig, const char* dest) { free(firm_buffer); return 1; } - + // add the decrypted magic FirmHeader* firm = (FirmHeader*) firm_buffer; memcpy(firm->dec_magic, dec_magic, sizeof(dec_magic)); - + // write decrypted FIRM to the destination file ShowProgress(1, 2, dest); if (fvx_qwrite(dest, firm_buffer, 0, firm_size, NULL) != FR_OK) { free(firm_buffer); return 1; } - + ShowProgress(2, 2, dest); free(firm_buffer); return 0; @@ -1174,13 +1174,13 @@ u32 CryptCdnFileBuffered(const char* orig, const char* dest, u16 crypto, void* b bool inplace = (strncmp(orig, dest, 256) == 0); TitleMetaData* tmd = (TitleMetaData*) buffer; TmdContentChunk* content_list = (TmdContentChunk*) (tmd + 1); - + // get name char* fname; fname = strrchr(orig, '/'); if (!fname) return 1; // will not happen fname++; - + // try to load TMD file char path_tmd[256]; if (!strrchr(fname, '.')) { @@ -1193,7 +1193,7 @@ u32 CryptCdnFileBuffered(const char* orig, const char* dest, u16 crypto, void* b snprintf(name_tmd, 256 - (name_tmd - path_tmd), "tmd"); if (LoadTmdFile(tmd, path_tmd) != 0) tmd = NULL; } else tmd = NULL; - + // load or build ticket Ticket* ticket = NULL; if (LoadCdnTicketFile(&ticket, orig) != 0) { @@ -1207,7 +1207,7 @@ u32 CryptCdnFileBuffered(const char* orig, const char* dest, u16 crypto, void* b return 1; } } - + // get titlekey u8 titlekey[0x10] = { 0xFF }; if (GetTitleKey(titlekey, ticket) != 0) { @@ -1216,13 +1216,13 @@ u32 CryptCdnFileBuffered(const char* orig, const char* dest, u16 crypto, void* b } free(ticket); - + // find (build fake) content chunk TmdContentChunk* chunk = NULL; if (!tmd) { chunk = content_list; memset(chunk, 0, sizeof(TmdContentChunk)); - chunk->type[1] = 0x01; // encrypted + chunk->type[1] = 0x01; // encrypted } else { u32 content_count = getbe16(tmd->content_count); u32 content_id = 0; @@ -1234,25 +1234,25 @@ u32 CryptCdnFileBuffered(const char* orig, const char* dest, u16 crypto, void* b } if (!chunk || !(getbe16(chunk->type) & 0x01)) return 1; } - + // actual crypto if (CryptNcchNcsdBossFirmFile(orig, dest, GAME_NUSCDN, crypto, 0, 0, chunk, titlekey) != 0) return 1; - + if (inplace && tmd) { // in that case, write the change to the TMD file, too u32 offset = ((u8*) chunk) - ((u8*) tmd); fvx_qwrite(path_tmd, chunk, offset, sizeof(TmdContentChunk), NULL); } - + return 0; } u32 CryptCdnFile(const char* orig, const char* dest, u16 crypto) { void* buffer = (void*) malloc(TMD_SIZE_MAX); if (!buffer) return 1; - + u32 ret = CryptCdnFileBuffered(orig, dest, crypto, buffer); - + free(buffer); return ret; } @@ -1263,7 +1263,7 @@ u32 CryptGameFile(const char* path, bool inplace, bool encrypt) { char dest[256]; char* destptr = (char*) path; u32 ret = 0; - + if (!inplace) { // build output name // build output name snprintf(dest, 256, OUTPUT_PATH "/"); @@ -1275,15 +1275,15 @@ u32 CryptGameFile(const char* path, bool inplace, bool encrypt) { } destptr = dest; } - + if (!CheckWritePermissions(destptr)) return 1; - + if (!inplace) { // ensure the output dir exists if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1; } - + if (filetype & GAME_CIA) ret = CryptCiaFile(path, destptr, crypto); else if (filetype & GAME_NUSCDN) @@ -1293,10 +1293,10 @@ u32 CryptGameFile(const char* path, bool inplace, bool encrypt) { else if (filetype & (GAME_NCCH|GAME_NCSD|GAME_BOSS)) ret = CryptNcchNcsdBossFirmFile(path, destptr, filetype, crypto, 0, 0, NULL, NULL); else ret = 1; - + if (!inplace && (ret != 0)) f_unlink(dest); // try to get rid of the borked file - + return ret; } @@ -1328,14 +1328,14 @@ u32 GetInstallDbsPath(char* path, const char* drv, const char* str) { // build the path snprintf(path, 256, "%2.2s/dbs/%s", drv, str); - + return 0; } u32 GetInstallPath(char* path, const char* drv, u64 tid64, const u8* content_id, const char* str) { static const u8 dlc_tid_high[] = { DLC_TID_HIGH }; u32 tid_high = (u32) ((tid64 >> 32) & 0xFFFFFFFF); - u32 tid_low = (u32) (tid64 & 0xFFFFFFFF); + u32 tid_low = (u32) (tid64 & 0xFFFFFFFF); bool dlc = (tid_high == getbe32(dlc_tid_high)); if ((*drv == '2') || (*drv == '5')) // TWL titles need TWL title ID @@ -1429,7 +1429,7 @@ u32 UninstallGameData(u64 tid64, bool remove_tie, bool remove_ticket, bool remov char path_data[256]; if (GetInstallPath(path_data, drv, tid64, NULL, remove_save ? NULL : "content") != 0) return 1; fvx_runlink(path_data); - + // clear leftovers if (GetInstallPath(path_data, drv, tid64, NULL, NULL) != 0) fvx_unlink(path_data); @@ -1516,7 +1516,7 @@ u32 InstallCiaContent(const char* drv, const char* path_content, u32 offset, u32 fvx_close(&ofile); return 1; } - + // ensure free space for destination file if ((fvx_lseek(&dfile, size) != FR_OK) || (fvx_tell(&dfile) != size) || @@ -1526,7 +1526,7 @@ u32 InstallCiaContent(const char* drv, const char* path_content, u32 offset, u32 fvx_unlink(dest); return 1; } - + // allocate buffer u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { @@ -1535,7 +1535,7 @@ u32 InstallCiaContent(const char* drv, const char* path_content, u32 offset, u32 fvx_unlink(dest); return 1; } - + // main loop starts here u8 ctr_in[16]; u8 ctr_out[16]; @@ -1557,18 +1557,18 @@ u32 InstallCiaContent(const char* drv, const char* path_content, u32 offset, u32 } u8 hash[0x20]; sha_get(hash); - + free(buffer); fvx_close(&ofile); fvx_close(&dfile); // did something go wrong? if (ret != 0) fvx_unlink(dest); - + // chunk size / chunk hash for (u32 i = 0; i < 8; i++) chunk->size[i] = (u8) (size >> (8*(7-i))); memcpy(chunk->hash, hash, 0x20); - + return ret; } @@ -1587,7 +1587,7 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { bool sdtie = ((*drv == 'A') || (*drv == 'B')); bool syscmd = (((*drv == '1') || (*drv == '4')) || (((*drv == '2') || (*drv == '5')) && (title_id[3] != 0x04))); - + char path_titledb[32]; char path_ticketdb[32]; char path_tmd[64]; @@ -1614,17 +1614,17 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { (DecryptNcch((u8*) exthdr, NCCH_EXTHDR_OFFSET, 0x400, ncch, NULL) != 0)) exthdr = NULL; } - + // build title info entry if ((ncch && (BuildTitleInfoEntryNcch(&tie, tmd, ncch, exthdr, sdtie) != 0)) || (!ncch && (BuildTitleInfoEntryTwl(&tie, tmd, (TwlHeader*) (void*) hdr_cnt0) != 0))) return 1; - + // build the cmd cmd = BuildAllocCmdData(tmd); if (!cmd) return 1; if (!syscmd) cmd->unknown = 0xFFFFFFFE; // mark this as custom built - + // generate all the paths snprintf(path_titledb, 32, "%2.2s/dbs/title.db", (*drv == '2') ? "1:" : *drv == '5' ? "4:" : drv); @@ -1643,7 +1643,7 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { return 1; } free(cmd); // we don't need this anymore - + // generate savedata u32 save_size = getle32(tmd->save_size); u32 twl_privsave_size = getle32(tmd->twl_privsave_size); @@ -1680,7 +1680,7 @@ u32 InstallCiaSystemData(CiaStub* cia, const char* drv) { InitImgFS(path_bak); return 1; } - + // restore old mount path InitImgFS(path_bak); @@ -1696,7 +1696,7 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset, bool ncch_decrypt = !force_legit; bool cia_encrypt = (force_legit && (getbe16(chunk->type) & 0x01)); if (!cia_encrypt) chunk->type[1] &= ~0x01; // remove crypto flag - + // open file(s) FIL ofile; FIL dfile; @@ -1712,7 +1712,7 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset, fvx_close(&ofile); return 1; } - + // ensure free space for destination file UINT offset_dest = fvx_size(&dfile); if ((fvx_lseek(&dfile, offset_dest + size) != FR_OK) || @@ -1722,20 +1722,20 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset, fvx_close(&dfile); return 1; } - + // check if NCCH crypto is available if (ncch_decrypt) { NcchHeader ncch; u8 ctr[16]; GetTmdCtr(ctr, chunk); if ((fvx_read(&ofile, &ncch, sizeof(NcchHeader), &bytes_read) != FR_OK) || - (cdn_decrypt && (DecryptCiaContentSequential((u8*) &ncch, 0x200, ctr, titlekey) != 0)) || + (cdn_decrypt && (DecryptCiaContentSequential((u8*) &ncch, 0x200, ctr, titlekey) != 0)) || (ValidateNcchHeader(&ncch) != 0) || (SetupNcchCrypto(&ncch, NCCH_NOCRYPTO) != 0)) ncch_decrypt = false; fvx_lseek(&ofile, offset); } - + // allocate buffer u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { @@ -1743,7 +1743,7 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset, fvx_close(&dfile); return 1; } - + // main loop starts here u8 ctr_in[16]; u8 ctr_out[16]; @@ -1766,19 +1766,19 @@ u32 InsertCiaContent(const char* path_cia, const char* path_content, u32 offset, } u8 hash[0x20]; sha_get(hash); - + free(buffer); fvx_close(&ofile); fvx_close(&dfile); - + // force legit? if (force_legit && (memcmp(hash, chunk->hash, 0x20) != 0)) return 1; if (force_legit && (getbe64(chunk->size) != size)) return 1; - + // chunk size / chunk hash for (u32 i = 0; i < 8; i++) chunk->size[i] = (u8) (size >> (8*(7-i))); memcpy(chunk->hash, hash, 0x20); - + return ret; } @@ -1795,10 +1795,10 @@ u32 InsertCiaMeta(const char* path_cia, CiaMeta* meta) { u32 InstallFromCiaFile(const char* path_cia, const char* path_dest) { CiaInfo info; u8 titlekey[16]; - + // start operation if (!ShowProgress(0, 0, path_cia)) return 1; - + // load CIA stub from origin CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); if (!cia) return 1; @@ -1808,7 +1808,7 @@ u32 InstallFromCiaFile(const char* path_cia, const char* path_dest) { free(cia); return 1; } - + // install CIA contents u8* title_id = cia->tmd.title_id; u32 content_count = getbe16(cia->tmd.content_count); @@ -1830,14 +1830,14 @@ u32 InstallFromCiaFile(const char* path_cia, const char* path_dest) { // fix for CIA console ID (if device ID different) if (getbe32(cia->ticket.console_id) != (&ARM9_ITCM->otp)->deviceId) memset(cia->ticket.console_id, 0x00, 4); - + // fix TMD hashes, install CIA system data if ((FixTmdHashes(&(cia->tmd)) != 0) || (InstallCiaSystemData(cia, path_dest) != 0)) { free(cia); return 1; } - + free(cia); return 0; } @@ -1845,10 +1845,10 @@ u32 InstallFromCiaFile(const char* path_cia, const char* path_dest) { u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, bool force_legit, bool cdn, void* buffer, bool install) { const u8 dlc_tid_high[] = { DLC_TID_HIGH }; CiaStub* cia = (CiaStub*) buffer; - + // Init progress bar if (!ShowProgress(0, 0, path_tmd)) return 1; - + // build the CIA stub memset(cia, 0, sizeof(CiaStub)); if ((BuildCiaHeader(&(cia->header), TICKET_COMMON_SIZE) != 0) || @@ -1858,7 +1858,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, (BuildFakeTicket((Ticket*)&(cia->ticket), cia->tmd.title_id) != 0)) { return 1; } - + // extract info from TMD TitleMetaData* tmd = &(cia->tmd); TmdContentChunk* content_list = cia->content_list; @@ -1866,7 +1866,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, u8* title_id = tmd->title_id; bool dlc = (memcmp(tmd->title_id, dlc_tid_high, sizeof(dlc_tid_high)) == 0); if (!content_count) return 1; - + // get (legit) ticket Ticket* ticket = (Ticket*)&(cia->ticket); bool src_emunand = ((*path_tmd == 'B') || (*path_tmd == '4')); @@ -1912,7 +1912,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, } else if (default_action == 1) { memcpy(ticket->titlekey, ticket_tmp->titlekey, 0x10); - ticket->commonkey_idx = ticket_tmp->commonkey_idx; + ticket->commonkey_idx = ticket_tmp->commonkey_idx; copy = false; } } @@ -1931,7 +1931,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, free(ticket_tmp); } else { Ticket* ticket_tmp = NULL; - if ((FindTitleKey(ticket, title_id) != 0) && + if ((FindTitleKey(ticket, title_id) != 0) && (FindTicket(&ticket_tmp, title_id, false, src_emunand) == 0)) { // we just copy the titlekey from a valid ticket (if we can) memcpy(ticket->titlekey, ticket_tmp->titlekey, 0x10); @@ -1939,7 +1939,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, } if (ticket_tmp) free(ticket_tmp); } - + // content path string char path_content[256]; char* name_content; @@ -1948,7 +1948,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, name_content = strrchr(path_content, '/'); if (!name_content) return 1; // will not happen name_content++; - + u8 present[(TMD_MAX_CONTENTS + 7) / 8]; memset(present, 0xFF, sizeof(present)); @@ -1969,7 +1969,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, cia->header.content_index[index/8] &= ~(1 << (7-(index%8))); } } - + // insert / install contents u8 titlekey[16] = { 0xFF }; if ((GetTitleKey(titlekey, (Ticket*)&(cia->ticket)) != 0) && force_legit) return 1; @@ -1991,7 +1991,7 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, } } } - + // try to build & insert meta, but ignore result if (!install) { CiaMeta* meta = (CiaMeta*) malloc(sizeof(CiaMeta)); @@ -2011,22 +2011,22 @@ u32 BuildInstallFromTmdFileBuffered(const char* path_tmd, const char* path_dest, free(meta); } } - + // write the CIA stub (take #2) if ((FixTmdHashes(tmd) != 0) || (!install && (WriteCiaStub(cia, path_dest) != 0)) || (install && (InstallCiaSystemData(cia, path_dest) != 0))) return 1; - + return 0; } u32 InstallFromTmdFile(const char* path_tmd, const char* path_dest) { void* buffer = (void*) malloc(sizeof(CiaStub)); if (!buffer) return 1; - + u32 ret = BuildInstallFromTmdFileBuffered(path_tmd, path_dest, true, true, buffer, true); - + free(buffer); return ret; } @@ -2034,9 +2034,9 @@ u32 InstallFromTmdFile(const char* path_tmd, const char* path_dest) { u32 BuildCiaFromTmdFile(const char* path_tmd, const char* path_dest, bool force_legit, bool cdn) { void* buffer = (void*) malloc(sizeof(CiaStub)); if (!buffer) return 1; - + u32 ret = BuildInstallFromTmdFileBuffered(path_tmd, path_dest, force_legit, cdn, buffer, false); - + free(buffer); return ret; } @@ -2058,10 +2058,10 @@ u32 BuildInstallFromNcchFile(const char* path_ncch, const char* path_dest, bool u8 title_id[8]; u32 save_size = 0; bool has_exthdr = false; - + // Init progress bar if (!ShowProgress(0, 0, path_ncch)) return 1; - + // load NCCH header / extheader, get save size && title id if (LoadNcchHeaders(&ncch, &exthdr, NULL, path_ncch, 0) == 0) { save_size = (u32) exthdr.savedata_size; @@ -2071,7 +2071,7 @@ u32 BuildInstallFromNcchFile(const char* path_ncch, const char* path_dest, bool } for (u32 i = 0; i < 8; i++) title_id[i] = (ncch.programId >> ((7-i)*8)) & 0xFF; - + // build the CIA stub CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); if (!cia) return 1; @@ -2085,7 +2085,7 @@ u32 BuildInstallFromNcchFile(const char* path_ncch, const char* path_dest, bool free(cia); return 1; } - + // insert / install NCCH content TmdContentChunk* chunk = cia->content_list; memset(chunk, 0, sizeof(TmdContentChunk)); // nothing else to do @@ -2094,7 +2094,7 @@ u32 BuildInstallFromNcchFile(const char* path_ncch, const char* path_dest, bool free(cia); return 1; } - + // optional stuff (proper titlekey / meta data) if (!install) { CiaMeta* meta = (CiaMeta*) malloc(sizeof(CiaMeta)); @@ -2104,7 +2104,7 @@ u32 BuildInstallFromNcchFile(const char* path_ncch, const char* path_dest, bool cia->header.size_meta = CIA_META_SIZE; free(meta); } - + // write the CIA stub (take #2) FindTitleKey((Ticket*)(&cia->ticket), title_id); if ((FixTmdHashes(&(cia->tmd)) != 0) || @@ -2114,7 +2114,7 @@ u32 BuildInstallFromNcchFile(const char* path_ncch, const char* path_dest, bool free(cia); return 1; } - + free(cia); return 0; } @@ -2125,10 +2125,10 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool NcchHeader ncch; u8 title_id[8]; u32 save_size = 0; - + // Init progress bar if (!ShowProgress(0, 0, path_ncsd)) return 1; - + // load NCSD header, get content count, title id u32 content_count = 0; if (LoadNcsdHeader(&ncsd, path_ncsd) != 0) return 1; @@ -2136,12 +2136,12 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool if (ncsd.partitions[i].size) content_count++; for (u32 i = 0; i < 8; i++) title_id[i] = (ncsd.mediaId >> ((7-i)*8)) & 0xFF; - + // load first content NCCH / extheader if (LoadNcchHeaders(&ncch, &exthdr, NULL, path_ncsd, NCSD_CNT0_OFFSET) != 0) return 1; save_size = (u32) exthdr.savedata_size; - + // build the CIA stub CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); if (!cia) return 1; @@ -2155,7 +2155,7 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool free(cia); return 1; } - + // insert / install NCSD content TmdContentChunk* chunk = cia->content_list; for (u32 i = 0; i < 3; i++) { @@ -2174,9 +2174,9 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool return 1; } } - + // optional stuff (proper titlekey / meta data) - if (!install) { + if (!install) { CiaMeta* meta = (CiaMeta*) malloc(sizeof(CiaMeta)); if (meta && (BuildCiaMeta(meta, &exthdr, NULL) == 0) && (LoadExeFsFile(meta->smdh, path_ncsd, NCSD_CNT0_OFFSET, "icon", sizeof(meta->smdh), NULL) == 0) && @@ -2194,7 +2194,7 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool memcpy((cia->tmd).title_version, title_version_le, 2); memcpy((cia->ticket).ticket_version, title_version_le, 2); } - + // write the CIA stub (take #2) FindTitleKey((Ticket*)&(cia->ticket), title_id); if ((FixTmdHashes(&(cia->tmd)) != 0) || @@ -2204,7 +2204,7 @@ u32 BuildInstallFromNcsdFile(const char* path_ncsd, const char* path_dest, bool free(cia); return 1; } - + free(cia); return 0; } @@ -2215,10 +2215,10 @@ u32 BuildInstallFromNdsFile(const char* path_nds, const char* path_dest, bool in u32 save_size = 0; u32 privsave_size = 0; u8 twl_flag = 0; - + // Init progress bar if (!ShowProgress(0, 0, path_nds)) return 1; - + // load TWL header, get save sizes, srl flag && title id if (fvx_qread(path_nds, &twl, 0, sizeof(TwlHeader), NULL) != FR_OK) return 1; @@ -2237,8 +2237,8 @@ u32 BuildInstallFromNdsFile(const char* path_nds, const char* path_dest, bool in // convert DSi title ID to 3DS title ID static const u8 tidhigh_3ds[4] = { 0x00, 0x04, 0x80, 0x04 }; - memcpy(title_id, tidhigh_3ds, 3); - + memcpy(title_id, tidhigh_3ds, 3); + // build the CIA stub CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); if (!cia) return 1; @@ -2252,7 +2252,7 @@ u32 BuildInstallFromNdsFile(const char* path_nds, const char* path_dest, bool in free(cia); return 1; } - + // insert / install NDS content TmdContentChunk* chunk = cia->content_list; memset(chunk, 0, sizeof(TmdContentChunk)); // nothing else to do @@ -2261,7 +2261,7 @@ u32 BuildInstallFromNdsFile(const char* path_nds, const char* path_dest, bool in free(cia); return 1; } - + // write the CIA stub (take #2) FindTitleKey((Ticket*)(&cia->ticket), title_id); if ((FixTmdHashes(&(cia->tmd)) != 0) || @@ -2271,7 +2271,7 @@ u32 BuildInstallFromNdsFile(const char* path_nds, const char* path_dest, bool in free(cia); return 1; } - + free(cia); return 0; } @@ -2280,7 +2280,7 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) { u64 filetype = IdentifyFileType(path); char dest[256]; u32 ret = 0; - + // build output name snprintf(dest, 256, OUTPUT_PATH "/"); char* dname = dest + strnlen(dest, 256); @@ -2295,14 +2295,14 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) { if (!dot || (dot < strrchr(dest, '/'))) dot = dest + strnlen(dest, 256); snprintf(dot, 16, ".%s", force_legit ? "legit.cia" : "cia"); - + if (!CheckWritePermissions(dest)) return 1; f_unlink(dest); // remove the file if it already exists - + // ensure the output dir exists if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1; - + // build CIA from game file if (filetype & GAME_TIE) ret = BuildCiaFromTieFile(path, dest, force_legit); @@ -2313,12 +2313,12 @@ u32 BuildCiaFromGameFile(const char* path, bool force_legit) { else if (filetype & GAME_NCSD) ret = BuildInstallFromNcsdFile(path, dest, false); else if ((filetype & GAME_NDS) && (filetype & FLAG_DSIW)) - ret = BuildInstallFromNdsFile(path, dest, false); + ret = BuildInstallFromNdsFile(path, dest, false); else ret = 1; - + if (ret != 0) // try to get rid of the borked file f_unlink(dest); - + return ret; } @@ -2380,7 +2380,7 @@ u32 InstallGameFile(const char* path, bool to_emunand) { // cleanup content folder before starting install ShowProgress(0, 0, path); UninstallGameData(tid64, false, false, false, to_emunand); - + // install game file if (filetype & GAME_CIA) ret = InstallFromCiaFile(path, drv); @@ -2391,12 +2391,12 @@ u32 InstallGameFile(const char* path, bool to_emunand) { else if (filetype & GAME_NCSD) ret = BuildInstallFromNcsdFile(path, drv, true); else if ((filetype & GAME_NDS) && (filetype & FLAG_DSIW)) - ret = BuildInstallFromNdsFile(path, drv, true); + ret = BuildInstallFromNdsFile(path, drv, true); else ret = 1; - + // cleanup on failed installs, but leave ticket and save untouched if (ret != 0) UninstallGameData(tid64, true, false, false, to_emunand); - + return ret; } @@ -2405,16 +2405,16 @@ u32 DumpCxiSrlFromTmdFile(const char* path) { u64 filetype = 0; char path_cxi[256]; char dest[256]; - + // prepare output name snprintf(dest, 256, OUTPUT_PATH "/"); char* dname = dest + strnlen(dest, 256); if (!CheckWritePermissions(dest)) return 1; - + // ensure the output dir exists if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1; - + // get path to CXI/SRL and decrypt (if encrypted) if ((strncmp(path + 1, ":/title/", 8) != 0) || (GetTmdContentPath(path_cxi, path) != 0) || @@ -2424,7 +2424,7 @@ u32 DumpCxiSrlFromTmdFile(const char* path) { if (*dname) fvx_unlink(dest); return 1; } - + return 0; } @@ -2435,7 +2435,7 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) strncpy(dest, path_out ? path_out : OUTPUT_PATH, 256); dest[255] = '\0'; if (!CheckWritePermissions(dest)) return 1; - + // NCSD handling u32 ncch_offset = 0; if (filetype & GAME_NCSD) { @@ -2450,7 +2450,7 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) NcchExtHeader exthdr; ExeFsHeader exefs; if (LoadNcchHeaders(&ncch, &exthdr, &exefs, path, ncch_offset) != 0) return 1; - + // find ".code" or ".firm" inside the ExeFS header u32 code_size = 0; u32 code_offset = 0; @@ -2462,7 +2462,7 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) code_offset = (ncch.offset_exefs * NCCH_MEDIA_UNIT) + sizeof(ExeFsHeader) + exefs.files[i].offset; } } - + // if code is compressed: find decompressed size u32 code_max_size = code_size; if (exthdr.flag & 0x1) { @@ -2474,27 +2474,27 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) u32 unc_size = GetCodeLzssUncompressedSize(footer, code_size); code_max_size = max(code_size, unc_size); } - + // allocate memory u8* code = (u8*) malloc(code_max_size); if (!code) { ShowPrompt(false, "Out of memory."); return 1; } - + // load .code if ((fvx_qread(path, code, ncch_offset + code_offset, code_size, NULL) != FR_OK) || (DecryptNcch(code, code_offset, code_size, &ncch, &exefs) != 0)) { free(code); return 1; } - + // decompress code (only if required) if ((exthdr.flag & 0x1) && (DecompressCodeLzss(code, &code_size, code_max_size) != 0)) { free(code); return 1; } - + // finalize output path (if not already final) char* ext = EXEFS_CODE_NAME; if (code_size >= 0x200) { @@ -2503,7 +2503,7 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) } if (extstr) strncpy(extstr, ext, 7); if (!path_out) snprintf(dest, 256, OUTPUT_PATH "/%016llX%s%s", ncch.programId, (exthdr.flag & 0x1) ? ".dec" : "", ext); - + // write output file fvx_unlink(dest); if (fvx_qwrite(dest, code, 0, code_size, NULL) != FR_OK) { @@ -2511,18 +2511,18 @@ u32 ExtractCodeFromCxiFile(const char* path, const char* path_out, char* extstr) free(code); return 1; } - + free(code); return 0; } u32 CompressCode(const char* path, const char* path_out) { char dest[256]; - + strncpy(dest, path_out ? path_out : OUTPUT_PATH, 255); if (!CheckWritePermissions(dest)) return 1; if (!path_out && (fvx_rmkdir(OUTPUT_PATH) != FR_OK)) return 1; - + // allocate memory u32 code_dec_size = fvx_qsize(path); u8* code_dec = (u8*) malloc(code_dec_size); @@ -2534,7 +2534,7 @@ u32 CompressCode(const char* path, const char* path_out) { ShowPrompt(false, "Out of memory."); return 1; } - + // load code.bin and compress code if ((fvx_qread(path, code_dec, 0, code_dec_size, NULL) != FR_OK) || (!CompressCodeLzss(code_dec, code_dec_size, code_cmp, &code_cmp_size))) { @@ -2542,7 +2542,7 @@ u32 CompressCode(const char* path, const char* path_out) { free(code_cmp); return 1; } - + // write output file fvx_unlink(dest); free(code_dec); @@ -2551,7 +2551,7 @@ u32 CompressCode(const char* path, const char* path_out) { free(code_cmp); return 1; } - + free(code_cmp); return 0; } @@ -2617,7 +2617,7 @@ u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) { } else if (filetype & GAME_NCSD) { // NCSD file if (LoadExeFsFile(smdh, path, NCSD_CNT0_OFFSET, "icon", sizeof(Smdh), NULL) == 0) return 0; } else if (filetype & GAME_CIA) { // CIA file - CiaInfo info; + CiaInfo info; if ((fvx_qread(path, &info, 0, 0x20, NULL) != FR_OK) || (GetCiaInfo(&info, (CiaHeader*) &info) != 0)) return 1; if ((info.offset_meta) && (fvx_qread(path, smdh, info.offset_meta + 0x400, sizeof(Smdh), NULL) == FR_OK)) return 0; @@ -2638,7 +2638,7 @@ u32 LoadSmdhFromGameFile(const char* path, Smdh* smdh) { return 1; return 0; } - + return 1; } @@ -2692,7 +2692,7 @@ u32 ShowGameFileTitleInfoF(const char* path, u16* screen, bool clear) { if (GetTieContentPath(path_content, path) != 0) return 1; path = path_content; } - + void* buffer = (void*) malloc(max(sizeof(Smdh), sizeof(TwlIconData))); Smdh* smdh = (Smdh*) buffer; TwlIconData* twl_icon = (TwlIconData*) buffer; @@ -2722,11 +2722,11 @@ u32 ShowGameFileTitleInfo(const char* path) { u32 ShowCiaCheckerInfo(const char* path) { CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); if (!cia) return 1; - + // path string char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - + // load CIA stub if (LoadCiaStub(cia, path) != 0) { ShowPrompt(false, "%s\nError: Probably not a CIA file", pathstr); @@ -2757,7 +2757,7 @@ u32 ShowCiaCheckerInfo(const char* path) { for (u32 i = 0; (i < content_count) && (i < TMD_MAX_CONTENTS); i++) { TmdContentChunk* chunk = &(cia->content_list[i]); u16 index = getbe16(chunk->index); - if (cnt_index[index/8] & (1 << (7-(index%8)))) content_found++; + if (cnt_index[index/8] & (1 << (7-(index%8)))) content_found++; else if (i == 0) missing_first = true; } @@ -2785,19 +2785,19 @@ u32 ShowCiaCheckerInfo(const char* path) { } free(cia); - return (state_ticket && state_tmd) ? 0 : 1; + return (state_ticket && state_tmd) ? 0 : 1; } u32 BuildNcchInfoXorpads(const char* destdir, const char* path) { FIL fp_info; FIL fp_xorpad; UINT bt; - + if (!CheckWritePermissions(destdir)) return 1; // warning: this will only build output dirs in the root dir (!) if ((f_stat(destdir, NULL) != FR_OK) && (f_mkdir(destdir) != FR_OK)) return 1; - + NcchInfoHeader info; u32 version = 0; u32 entry_size = 0; @@ -2813,7 +2813,7 @@ u32 BuildNcchInfoXorpads(const char* destdir, const char* path) { version = GetNcchInfoVersion(&info); entry_size = (version == 3) ? NCCHINFO_V3_SIZE : sizeof(NcchInfoEntry); if (!version) ret = 1; - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) ret = 1; for (u32 i = 0; (i < info.n_entries) && (ret == 0); i++) { @@ -2822,7 +2822,7 @@ u32 BuildNcchInfoXorpads(const char* destdir, const char* path) { (bt != entry_size)) ret = 1; if (FixNcchInfoEntry(&entry, version) != 0) ret = 1; if (ret != 0) break; - + char dest[256]; // 256 is the maximum length of a full path snprintf(dest, 256, "%s/%s", destdir, entry.filename); if (fvx_open(&fp_xorpad, dest, FA_WRITE | FA_CREATE_ALWAYS) == FR_OK) { @@ -2837,7 +2837,7 @@ u32 BuildNcchInfoXorpads(const char* destdir, const char* path) { } else ret = 1; if (ret != 0) f_unlink(dest); // get rid of the borked file } - + if (buffer) free(buffer); fvx_close(&fp_info); return ret; @@ -2846,7 +2846,7 @@ u32 BuildNcchInfoXorpads(const char* destdir, const char* path) { u32 GetHealthAndSafetyPaths(const char* drv, char* path_cxi, char* path_bak) { static const u32 tidlow_hs_o3ds[] = { 0x00020300, 0x00021300, 0x00022300, 0, 0x00026300, 0x00027300, 0x00028300 }; static const u32 tidlow_hs_n3ds[] = { 0x20020300, 0x20021300, 0x20022300, 0, 0, 0x20027300, 0 }; - + // get H&S title id low u32 tidlow_hs = 0; for (char secchar = 'C'; secchar >= 'A'; secchar--) { @@ -2865,7 +2865,7 @@ u32 GetHealthAndSafetyPaths(const char* drv, char* path_cxi, char* path_bak) { break; } if (!tidlow_hs) return 1; - + // build paths if (path_cxi) *path_cxi = '\0'; if (path_bak) *path_bak = '\0'; @@ -2881,7 +2881,7 @@ u32 GetHealthAndSafetyPaths(const char* drv, char* path_cxi, char* path_bak) { break; } free(tmd); - + return ((path_cxi && !*path_cxi) || (path_bak && !*path_bak)) ? 1 : 0; } @@ -2894,33 +2894,33 @@ u32 CheckHealthAndSafetyInject(const char* hsdrv) { u32 InjectHealthAndSafety(const char* path, const char* destdrv) { NcchHeader ncch; NcchExtHeader exthdr; - + // write permissions if (!CheckWritePermissions(destdrv)) return 1; - + // legacy stuff - remove mark file char path_mrk[32] = { 0 }; snprintf(path_mrk, 32, "%s/%s", destdrv, "__gm9_hsbak.pth"); f_unlink(path_mrk); - + // get H&S paths char path_cxi[64] = { 0 }; char path_bak[64] = { 0 }; if (GetHealthAndSafetyPaths(destdrv, path_cxi, path_bak) != 0) return 1; - + if (!path) { // if path == NULL -> restore H&S from backup if (f_stat(path_bak, NULL) != FR_OK) return 1; f_unlink(path_cxi); f_rename(path_bak, path_cxi); return 0; } - + // check input file / crypto if ((LoadNcchHeaders(&ncch, &exthdr, NULL, path, 0) != 0) || !(NCCH_IS_CXI(&ncch)) || (SetupNcchCrypto(&ncch, NCCH_NOCRYPTO) != 0)) return 1; - + // check crypto, get sig if ((LoadNcchHeaders(&ncch, &exthdr, NULL, path_cxi, 0) != 0) || (SetupNcchCrypto(&ncch, NCCH_NOCRYPTO) != 0) || !(NCCH_IS_CXI(&ncch))) @@ -2929,17 +2929,17 @@ u32 InjectHealthAndSafety(const char* path, const char* destdrv) { memcpy(sig, ncch.signature, 0x100); u16 crypto = NCCH_GET_CRYPTO(&ncch); u64 tid_hs = ncch.programId; - + // make a backup copy if there is not already one (point of no return) if (f_stat(path_bak, NULL) != FR_OK) { if (f_rename(path_cxi, path_bak) != FR_OK) return 1; } else f_unlink(path_cxi); - + // copy / decrypt the source CXI u32 ret = 0; if (CryptNcchNcsdBossFirmFile(path, path_cxi, GAME_NCCH, CRYPTO_DECRYPT, 0, 0, NULL, NULL) != 0) ret = 1; - + // fix up the injected H&S NCCH header / extheader (copy H&S signature, title ID to multiple locations) // also set savedata size to zero (thanks @TurdPooCharger) if ((ret == 0) && (LoadNcchHeaders(&ncch, &exthdr, NULL, path_cxi, 0) == 0)) { @@ -2955,16 +2955,16 @@ u32 InjectHealthAndSafety(const char* path, const char* destdrv) { (fvx_qwrite(path_cxi, &exthdr, NCCH_EXTHDR_OFFSET, sizeof(NcchExtHeader), NULL) != FR_OK)) ret = 1; } else ret = 1; - + // encrypt the CXI in place if (CryptNcchNcsdBossFirmFile(path_cxi, path_cxi, GAME_NCCH, crypto, 0, 0, NULL, NULL) != 0) ret = 1; - + if (ret != 0) { // in case of failure: try recover f_unlink(path_cxi); f_rename(path_bak, path_cxi); } - + return ret; } @@ -2972,22 +2972,22 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) { static TitleKeysInfo* tik_info = NULL; const char* path_out = (dec) ? OUTPUT_PATH "/" TIKDB_NAME_DEC : OUTPUT_PATH "/" TIKDB_NAME_ENC; const char* path_in = path; - + // write permissions if (!CheckWritePermissions(path_out)) return 1; - + if (!path_in && !dump) { // no input path given - initialize if (!tik_info) tik_info = (TitleKeysInfo*) malloc(STD_BUFFER_SIZE); if (!tik_info) return 1; memset(tik_info, 0, 16); - + if ((fvx_stat(path_out, NULL) == FR_OK) && (ShowPrompt(true, "%s\nOutput file already exists.\nUpdate this?", path_out))) path_in = path_out; else return 0; } - + u64 filetype = path_in ? IdentifyFileType(path_in) : 0; if (filetype & GAME_TICKET) { TicketCommon ticket; @@ -3004,12 +3004,12 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) { FILINFO fno; TicketCommon ticket; char tik_path[64]; - + if (fvx_opendir(&dir, "T:/eshop") != FR_OK) { InitImgFS(NULL); return 1; } - + while ((fvx_readdir(&dir, &fno) == FR_OK) && *(fno.fname)) { snprintf(tik_path, 64, "T:/eshop/%s", fno.fname); if (fvx_qread(tik_path, &ticket, 0, TICKET_COMMON_SIZE, NULL) != FR_OK) @@ -3017,14 +3017,14 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) { if (TIKDB_SIZE(tik_info) + 32 > STD_BUFFER_SIZE) break; // no error message AddTicketToInfo(tik_info, (Ticket*) &ticket, dec); // ignore result } - + fvx_closedir(&dir); - + if (fvx_opendir(&dir, "T:/system") != FR_OK) { InitImgFS(NULL); return 1; } - + while ((fvx_readdir(&dir, &fno) == FR_OK) && *(fno.fname)) { snprintf(tik_path, 64, "T:/system/%s", fno.fname); if ((fvx_qread(tik_path, &ticket, 0, TICKET_COMMON_SIZE, NULL) != FR_OK) || @@ -3033,35 +3033,35 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) { if (TIKDB_SIZE(tik_info) + 32 > STD_BUFFER_SIZE) break; // no error message AddTicketToInfo(tik_info, (Ticket*) &ticket, dec); // ignore result } - + fvx_closedir(&dir); - + InitImgFS(NULL); } else if (filetype & BIN_TIKDB) { TitleKeysInfo* tik_info_merge = (TitleKeysInfo*) malloc(STD_BUFFER_SIZE); if (!tik_info_merge) return 1; - + UINT br; if ((fvx_qread(path_in, tik_info_merge, 0, STD_BUFFER_SIZE, &br) != FR_OK) || (TIKDB_SIZE(tik_info_merge) != br)) { free(tik_info_merge); return 1; } - + // merge and rebuild TitleKeyInfo u32 n_entries = tik_info_merge->n_entries; TitleKeyEntry* tik = tik_info_merge->entries; for (u32 i = 0; i < n_entries; i++, tik++) { if (TIKDB_SIZE(tik_info) + 32 > STD_BUFFER_SIZE) break; // no error message - AddTitleKeyToInfo(tik_info, tik, !(filetype & FLAG_ENC), dec, false); // ignore result + AddTitleKeyToInfo(tik_info, tik, !(filetype & FLAG_ENC), dec, false); // ignore result } - + free(tik_info_merge); } - + if (dump) { u32 dump_size = TIKDB_SIZE(tik_info); - + if (dump_size > 16) { if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) // ensure the output dir exists return 1; @@ -3069,11 +3069,11 @@ u32 BuildTitleKeyInfo(const char* path, bool dec, bool dump) { if ((dump_size <= 16) || (fvx_qwrite(path_out, tik_info, 0, dump_size, NULL) != FR_OK)) return 1; } - + free(tik_info); tik_info = NULL; } - + return 0; } @@ -3082,26 +3082,26 @@ u32 BuildSeedInfo(const char* path, bool dump) { const char* path_out = OUTPUT_PATH "/" SEEDDB_NAME; const char* path_in = path; u32 inputtype = 0; // 0 -> none, 1 -> seeddb.bin, 2 -> seed system save - + // write permissions if (!CheckWritePermissions(path_out)) return 1; - + if (!path_in && !dump) { // no input path given - initialize if (!seed_info) seed_info = (SeedInfo*) malloc(STD_BUFFER_SIZE); if (!seed_info) return 1; memset(seed_info, 0, 16); - + if ((fvx_stat(path_out, NULL) == FR_OK) && (ShowPrompt(true, "%s\nOutput file already exists.\nUpdate this?", path_out))) { path_in = path_out; inputtype = 1; } else return 0; } - + // seed info has to be allocated at this point if (!seed_info) return 1; - + char path_str[128]; if (path_in && (strnlen(path_in, 16) == 2)) { // when only a drive is given... // grab the key Y from movable.sed @@ -3117,36 +3117,36 @@ u32 BuildSeedInfo(const char* path, bool dump) { path_in = path_str; inputtype = 2; } - + if (inputtype == 1) { // seeddb.bin input SeedInfo* seed_info_merge = (SeedInfo*) malloc(STD_BUFFER_SIZE); if (!seed_info_merge) return 1; - + UINT br; if ((fvx_qread(path_in, seed_info_merge, 0, STD_BUFFER_SIZE, &br) != FR_OK) || (SEEDDB_SIZE(seed_info_merge) != br)) { free(seed_info_merge); return 1; } - + // merge and rebuild SeedInfo u32 n_entries = seed_info_merge->n_entries; SeedInfoEntry* seed = seed_info_merge->entries; for (u32 i = 0; i < n_entries; i++, seed++) { if (SEEDDB_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message - AddSeedToDb(seed_info, seed); // ignore result + AddSeedToDb(seed_info, seed); // ignore result } - + free(seed_info_merge); } else if (inputtype == 2) { // seed system save input u8* seedsave = (u8*) malloc(SEEDSAVE_AREA_SIZE); if (!seedsave) return 1; - + if (ReadDisaDiffIvfcLvl4(path_in, NULL, SEEDSAVE_AREA_OFFSET, SEEDSAVE_AREA_SIZE, seedsave) != SEEDSAVE_AREA_SIZE) { free(seedsave); return 1; } - + SeedInfoEntry seed = { 0 }; for (u32 s = 0; s < SEEDSAVE_MAX_ENTRIES; s++) { seed.titleId = getle64(seedsave + (s*8)); @@ -3154,16 +3154,16 @@ u32 BuildSeedInfo(const char* path, bool dump) { if (((seed.titleId >> 32) != 0x00040000) || (!getle64(seed.seed) && !getle64(seed.seed + 8))) continue; if (SEEDDB_SIZE(seed_info) + 32 > STD_BUFFER_SIZE) break; // no error message - AddSeedToDb(seed_info, &seed); // ignore result + AddSeedToDb(seed_info, &seed); // ignore result } - + free(seedsave); } - + if (dump) { u32 dump_size = SEEDDB_SIZE(seed_info); u32 ret = 0; - + if (dump_size > 16) { if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) // ensure the output dir exists ret = 1; @@ -3171,18 +3171,18 @@ u32 BuildSeedInfo(const char* path, bool dump) { if (fvx_qwrite(path_out, seed_info, 0, dump_size, NULL) != FR_OK) ret = 1; } else ret = 1; - + free(seed_info); seed_info = NULL; return ret; } - + return 0; } u32 LoadNcchFromGameFile(const char* path, NcchHeader* ncch) { u64 filetype = IdentifyFileType(path); - + if (filetype & GAME_NCCH) { if ((fvx_qread(path, ncch, 0, sizeof(NcchHeader), NULL) == FR_OK) && (ValidateNcchHeader(ncch) == 0)) return 0; @@ -3192,14 +3192,14 @@ u32 LoadNcchFromGameFile(const char* path, NcchHeader* ncch) { } else if (filetype & GAME_CIA) { CiaStub* cia = (CiaStub*) malloc(sizeof(CiaStub)); CiaInfo info; - + // load CIA stub from path if ((LoadCiaStub(cia, path) != 0) || (GetCiaInfo(&info, &(cia->header)) != 0)) { free(cia); return 1; } - + // decrypt / load NCCH header from first CIA content u32 ret = 1; if (getbe16(cia->tmd.content_count)) { @@ -3221,11 +3221,11 @@ u32 LoadNcchFromGameFile(const char* path, NcchHeader* ncch) { } if (ValidateNcchHeader(ncch) == 0) ret = 0; } - + free(cia); return ret; } - + return 1; } @@ -3238,7 +3238,7 @@ u32 GetGoodName(char* name, const char* path, bool quick) { // name scheme (NTR): (). // name scheme (TWL): (). // name scheme (AGB): (). - + const char* path_donor = path; u64 type_donor = IdentifyFileType(path); char* ext = @@ -3250,7 +3250,7 @@ u32 GetGoodName(char* name, const char* path, bool quick) { (type_donor & GAME_TMD) ? "tmd" : (type_donor & GAME_TIE) ? "tie" : ""; if (!*ext) return 1; - + char appid_str[1 + 8 + 1] = { 0 }; // handling for NCCH / NDS in "?:/title" paths if ((type_donor & (GAME_NCCH|GAME_NDS)) && (strncmp(path + 1, ":/title/", 8) == 0)) { char* name = strrchr(path, '/'); @@ -3258,7 +3258,7 @@ u32 GetGoodName(char* name, const char* path, bool quick) { *appid_str = '.'; strncpy(appid_str + 1, name, 8); } - + char path_content[256]; if (type_donor & GAME_TMD) { if (GetTmdContentPath(path_content, path) != 0) return 1; @@ -3269,7 +3269,7 @@ u32 GetGoodName(char* name, const char* path, bool quick) { path_donor = path_content; type_donor = IdentifyFileType(path_donor); } - + if (type_donor & GAME_GBA) { // AGB AgbHeader agb; if (fvx_qread(path_donor, &agb, 0, sizeof(AgbHeader), NULL) != FR_OK) return 1; @@ -3289,7 +3289,7 @@ u32 GetGoodName(char* name, const char* path, bool quick) { if (GetTwlTitle(title_name, &icon) != 0) return 1; char* linebrk = strchr(title_name, '\n'); if (linebrk) *linebrk = '\0'; - + if (twl.unit_code & 0x02) { // TWL char region[8] = { 0 }; if (twl.region_flags == TWL_REGION_FREE) snprintf(region, 8, "W"); @@ -3301,7 +3301,7 @@ u32 GetGoodName(char* name, const char* path, bool quick) { (twl.region_flags & REGION_MASK_KOR) ? "K" : ""); if (strncmp(region, "JUECK", 8) == 0) snprintf(region, 8, "W"); if (!*region) snprintf(region, 8, "UNK"); - + char* unit_str = (twl.unit_code == TWL_UNITCODE_TWLNTR) ? "DSi Enhanced" : "DSi Exclusive"; snprintf(name, 128, "%016llX %s (TWL-%.4s) (%s) (%s).%s", twl.title_id, title_name, twl.game_code, unit_str, region, ext); @@ -3318,7 +3318,7 @@ u32 GetGoodName(char* name, const char* path, bool quick) { } else { char title_name[0x40+1] = { 0 }; if (GetSmdhDescShort(title_name, &smdh) != 0) return 1; - + char region[8] = { 0 }; if (smdh.region_lockout == SMDH_REGION_FREE) snprintf(region, 8, "W"); else snprintf(region, 8, "%s%s%s%s%s%s", @@ -3330,25 +3330,25 @@ u32 GetGoodName(char* name, const char* path, bool quick) { (smdh.region_lockout & REGION_MASK_TWN) ? "T" : ""); if (strncmp(region, "JUECKT", 8) == 0) snprintf(region, 8, "W"); if (!*region) snprintf(region, 8, "UNK"); - + snprintf(name, 128, "%016llX%s %s (%.16s) (%s).%s", ncch.programId, appid_str, title_name, ncch.productcode, region, ext); } } else return 1; - + // remove illegal chars from filename for (char* c = name; *c; c++) { if ((*c == ':') || (*c == '/') || (*c == '\\') || (*c == '"') || (*c == '*') || (*c == '?') || (*c == '\n') || (*c == '\r')) *c = ' '; } - + // remove double spaces from filename char* s = name; for (char* c = name; *s; c++, s++) { while ((*c == ' ') && (*(c+1) == ' ')) c++; *s = *c; } - + return 0; } diff --git a/arm9/source/utils/keydbutil.c b/arm9/source/utils/keydbutil.c index d271bab..dbc38eb 100644 --- a/arm9/source/utils/keydbutil.c +++ b/arm9/source/utils/keydbutil.c @@ -8,45 +8,45 @@ u32 CryptAesKeyDb(const char* path, bool inplace, bool encrypt) { AesKeyInfo* keydb = NULL; const char* path_out = (inplace) ? path : OUTPUT_PATH "/" KEYDB_NAME; - + // write permissions if (!CheckWritePermissions(path_out)) return 1; - + if (!inplace) { // ensure the output dir exists if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1; } - + // check key database size u32 fsize = fvx_qsize(path); if (!fsize || (fsize % sizeof(AesKeyInfo)) || (fsize > MAX_KEYDB_SIZE)) return 1; - + keydb = (AesKeyInfo*) malloc(fsize); if (!keydb) return 1; - + // load key database if (fvx_qread(path, keydb, 0, fsize, NULL) != FR_OK) { free(keydb); return 1; } - + // en-/decrypt keys u32 n_keys = fsize / sizeof(AesKeyInfo); for (u32 i = 0; i < n_keys; i++) { if ((bool) keydb[i].isEncrypted == !encrypt) CryptAesKeyInfo(&(keydb[i])); } - + // dump key database if (!inplace) f_unlink(path_out); if (fvx_qwrite(path_out, keydb, 0, fsize, NULL) != FR_OK) { free(keydb); return 1; } - + free(keydb); return 0; } @@ -72,35 +72,35 @@ u32 BuildKeyDb(const char* path, bool dump) { static AesKeyInfo* key_info = NULL; const char* path_out = OUTPUT_PATH "/" KEYDB_NAME; const char* path_in = path; - + // write permissions if (!CheckWritePermissions(path_out)) return 1; - + if (!path_in && !dump) { // no input path given - initialize if (!key_info) key_info = (AesKeyInfo*) malloc(STD_BUFFER_SIZE); if (!key_info) return 1; memset(key_info, 0xFF, sizeof(AesKeyInfo)); - + AddKeyToDb(key_info, NULL); if ((fvx_stat(path_out, NULL) == FR_OK) && (ShowPrompt(true, "%s\nOutput file already exists.\nUpdate this?", path_out))) path_in = path_out; else return 0; } - + // key info has to be allocated at this point if (!key_info) return 1; - + u64 filetype = path_in ? IdentifyFileType(path_in) : 0; if (filetype & BIN_KEYDB) { // AES key database u32 fsize = fvx_qsize(path_in); if ((fsize % sizeof(AesKeyInfo)) || (fsize > MAX_KEYDB_SIZE)) return 1; - + u32 n_keys = fsize / sizeof(AesKeyInfo); u32 merged_keys = 0; - + AesKeyInfo* key_info_merge = (AesKeyInfo*) malloc(fsize); if (fvx_qread(path_in, key_info_merge, 0, fsize, NULL) == FR_OK) { for (u32 i = 0; i < n_keys; i++) { @@ -110,7 +110,7 @@ u32 BuildKeyDb(const char* path, bool dump) { merged_keys++; } } - + free(key_info_merge); if (merged_keys < n_keys) return 1; } else if (filetype & BIN_LEGKEY) { // legacy key file @@ -118,17 +118,17 @@ u32 BuildKeyDb(const char* path, bool dump) { unsigned int keyslot = 0xFF; char typestr[32] = { 0 }; char* name_in = strrchr(path_in, '/'); - + memset(&key, 0, sizeof(AesKeyInfo)); key.type = 'N'; if (!name_in || (strnlen(++name_in, 32) > 24)) return 1; // safety if ((sscanf(name_in, "slot0x%02XKey%31s", &keyslot, typestr) != 2) && (sscanf(name_in, "slot0x%02Xkey%31s", &keyslot, typestr) != 2)) return 1; - + char* ext = strchr(typestr, '.'); if (!ext) return 1; *(ext++) = '\0'; - + if ((*typestr == 'X') || (*typestr == 'Y')) { key.type = *typestr; strncpy(key.id, typestr + 1, 10); @@ -143,7 +143,7 @@ u32 BuildKeyDb(const char* path, bool dump) { if (fvx_qread(path_in, key.key, 0, 16, NULL) != FR_OK) return 1; if (AddKeyToDb(key_info, &key) != 0) return 1; } - + if (dump) { u32 dump_size = 0; for (AesKeyInfo* key = key_info; key->slot <= 0x40; key++) { @@ -151,7 +151,7 @@ u32 BuildKeyDb(const char* path, bool dump) { if (dump_size_next > MAX_KEYDB_SIZE) break; dump_size = dump_size_next; } - + if (dump_size) { if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) // ensure the output dir exists return 1; @@ -159,10 +159,10 @@ u32 BuildKeyDb(const char* path, bool dump) { if (fvx_qwrite(path_out, key_info, 0, dump_size, NULL) != FR_OK) return 1; } - + free(key_info); key_info = NULL; } - + return 0; } diff --git a/arm9/source/utils/nandcmac.c b/arm9/source/utils/nandcmac.c index 6ef5ff5..e3ae4fa 100644 --- a/arm9/source/utils/nandcmac.c +++ b/arm9/source/utils/nandcmac.c @@ -55,15 +55,15 @@ u32 SetupSlot0x30(char drv) { u8 keyy[16] __attribute__((aligned(32))); char movable_path[32]; - + if ((drv == 'A') || (drv == 'S')) drv = '1'; else if ((drv == 'B') || (drv == 'E')) drv = '4'; - + snprintf(movable_path, 32, "%c:/private/movable.sed", drv); if (fvx_qread(movable_path, keyy, 0x110, 0x10, NULL) != FR_OK) return 1; setup_aeskeyY(0x30, keyy); use_aeskey(0x30); - + return 0; } @@ -117,12 +117,12 @@ u32 LocateAgbSaveSdCurrentSlot(const char* path, AgbSaveHeader* agbsave) { u32 CheckCmacHeader(const char* path) { u8 cmac_hdr[0x100]; UINT br; - + if ((fvx_qread(path, cmac_hdr, 0, 0x100, &br) != FR_OK) || (br != 0x100)) return 1; for (u32 i = 0x10; i < 0x100; i++) if (cmac_hdr[i] != 0x00) return 1; - + return 0; } @@ -133,14 +133,14 @@ u32 CheckCmacPath(const char* path) { u32 ReadWriteFileCmac(const char* path, u8* cmac, bool do_write, bool check_perms) { u32 cmac_type = CalculateFileCmac(path, NULL); u32 offset = 0; - + if (!cmac_type) return 1; else if (cmac_type == CMAC_MOVABLE) offset = 0x130; else if (cmac_type == CMAC_AGBSAVE) offset = 0x010; else if (cmac_type == CMAC_AGBSAVE_SD) offset = LocateAgbSaveSdCurrentSlot(path, NULL) + 0x10; else if ((cmac_type == CMAC_CMD_SD) || (cmac_type == CMAC_CMD_TWLN)) return 1; // can't do that here else offset = 0x000; - + if (do_write && check_perms && !CheckWritePermissions(path)) return 1; if (!do_write) return (fvx_qread(path, cmac, offset, 0x10, NULL) != FR_OK) ? 1 : 0; else return (fvx_qwrite(path, cmac, offset, 0x10, NULL) != FR_OK) ? 1 : 0; @@ -155,13 +155,13 @@ u32 CalculateFileCmac(const char* path, u8* cmac) { u32 sid; // save ID / various uses char* name; char* ext; - + name = strrchr(path, '/'); // filename if (!name) return 0; // will not happen name++; ext = strrchr(name, '.'); // extension if (ext) ext++; - + if ((drv == 'A') || (drv == 'B')) { // data installed on SD if (sscanf(path, "%c:/extdata/%08lx/%08lx/%08lx/%08lx", &drv, &xid_high, &xid_low, &fid_high, &fid_low) == 5) { sid = 1; @@ -191,7 +191,7 @@ u32 CalculateFileCmac(const char* path, u8* cmac) { cmac_type = CMAC_CMD_TWLN; // this is not supported (yet), it's in here just for detection } } - + if (!cmac_type) { // path independent stuff const char* db_names[] = { SYS_DB_NAMES }; for (sid = 0; sid < sizeof(db_names) / sizeof(char*); sid++) @@ -203,28 +203,28 @@ u32 CalculateFileCmac(const char* path, u8* cmac) { else if (strncasecmp(name, "agbsave.bin", 16) == 0) cmac_type = CMAC_AGBSAVE; } - + // exit with cmac_type if (u8*) cmac is NULL // somewhat hacky, but can be used to check if file has a CMAC if (!cmac) return cmac_type; else if ((cmac_type == CMAC_CMD_SD) || (cmac_type == CMAC_CMD_TWLN)) return 1; else if (!cmac_type) return 1; - + static const u32 cmac_keyslot[] = { CMAC_KEYSLOT }; - u8 hashdata[0x200] __attribute__((aligned(4))); + u8 hashdata[0x200] __attribute__((aligned(4))); u32 keyslot = cmac_keyslot[cmac_type]; u32 hashsize = 0; - + // setup slot 0x30 via movable.sed if ((keyslot == 0x30) && (SetupSlot0x30(drv) != 0)) return 1; - + // build hash data block, get size if ((cmac_type == CMAC_AGBSAVE) || (cmac_type == CMAC_AGBSAVE_SD)) { // agbsaves AgbSaveHeader* agbsave = (AgbSaveHeader*) malloc(AGBSAVE_MAX_SIZE); u32 offset = 0; UINT br; - + if (!agbsave) return 1; if (cmac_type == CMAC_AGBSAVE_SD) offset = LocateAgbSaveSdCurrentSlot(path, NULL); if ((fvx_qread(path, agbsave, offset, AGBSAVE_MAX_SIZE, &br) != FR_OK) || (br < 0x200) || @@ -232,7 +232,7 @@ u32 CalculateFileCmac(const char* path, u8* cmac) { free(agbsave); return 1; } - + u32 ret = FixAgbSaveCmac(agbsave, cmac, (cmac_type == CMAC_AGBSAVE) ? NULL : path); free(agbsave); return ret; @@ -275,14 +275,14 @@ u32 CalculateFileCmac(const char* path, u8* cmac) { hashsize = 0x10C; } } - + // calculate CMAC u8 shasum[32]; if (!hashsize) return 1; sha_quick(shasum, hashdata, hashsize, SHA256_MODE); use_aeskey(keyslot); aes_cmac(shasum, cmac, 2); - + return 0; } @@ -311,11 +311,11 @@ u32 FixFileCmac(const char* path, bool check_perms) { u32 FixAgbSaveCmac(void* data, u8* cmac, const char* sddrv) { AgbSaveHeader* agbsave = (AgbSaveHeader*) (void*) data; u8 temp[0x30] __attribute__((aligned(4))); // final hash @temp+0x00 - + // safety check if (ValidateAgbSaveHeader(agbsave) != 0) return 1; - + if (!sddrv) { // NAND partition mode sha_quick(temp + 0x00, (u8*) data + 0x30, (0x200 - 0x30) + agbsave->save_size, SHA256_MODE); } else { @@ -325,7 +325,7 @@ u32 FixAgbSaveCmac(void* data, u8* cmac, const char* sddrv) { // this won't work on devkits(!!!) const char* cmac_savetype[] = { CMAC_SAVETYPE }; if (SetupSlot0x30(*sddrv) != 0) return 1; - + // first hash (hash0 = AGBSAVE_hash) sha_quick(temp + 0x08, (u8*) data + 0x30, (0x200 - 0x30) + agbsave->save_size, SHA256_MODE); // second hash (hash1 = CTR-SAV0 + hash0) @@ -336,11 +336,11 @@ u32 FixAgbSaveCmac(void* data, u8* cmac, const char* sddrv) { memcpy(temp + 0x08, &(agbsave->title_id), 8); sha_quick(temp + 0x00, temp, 0x30, SHA256_MODE); } - + use_aeskey((sddrv) ? 0x30 : 0x24); aes_cmac(temp, &(agbsave->cmac), 2); if (cmac) memcpy(cmac, &(agbsave->cmac), 0x10); - + return 0; } @@ -368,7 +368,7 @@ u32 CheckFixCmdCmac(const char* path, bool fix, bool check_perms) { u64 cmd_size = fvx_qsize(path); u8* cmd_data = malloc(cmd_size); CmdHeader* cmd = (CmdHeader*) (void*) cmd_data; - + // check for out of memory if (cmd_data == NULL) return 1; @@ -454,13 +454,13 @@ u32 RecursiveFixFileCmacWorker(char* path) { FILINFO fno; DIR pdir; u32 err = 0; - + if (fvx_opendir(&pdir, path) == FR_OK) { // process folder contents char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); char* fname = path + strnlen(path, 255); *(fname++) = '/'; - + ShowString("%s\nFixing CMACs, please wait...", pathstr); while (f_readdir(&pdir, &fno) == FR_OK) { if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0)) @@ -479,16 +479,16 @@ u32 RecursiveFixFileCmacWorker(char* path) { *(--fname) = '\0'; } else if (CheckCmacPath(path) == 0) // fix single file CMAC return FixFileCmac(path, true); - + return err; } u32 RecursiveFixFileCmac(const char* path) { // create a fixed up local path // (this is highly path sensitive) - char lpath[256]; + char lpath[256]; char* p = (char*) path; - lpath[255] = '\0'; + lpath[255] = '\0'; for (u32 i = 0; i < 255; i++) { lpath[i] = *(p++); while ((lpath[i] == '/') && (*p == '/')) p++; diff --git a/arm9/source/utils/nandutil.c b/arm9/source/utils/nandutil.c index ed28070..ce6f59b 100644 --- a/arm9/source/utils/nandutil.c +++ b/arm9/source/utils/nandutil.c @@ -50,7 +50,7 @@ u32 BuildEssentialBackup(const char* path, EssentialBackup* essential) { }; memset(essential, 0, sizeof(EssentialBackup)); memcpy(essential, filelist, sizeof(filelist)); - + // backup current mount path, mount new path char path_store[256] = { 0 }; char* path_bak = NULL; @@ -61,7 +61,7 @@ u32 BuildEssentialBackup(const char* path, EssentialBackup* essential) { InitImgFS(path_bak); return 1; } - + // read four files ExeFsFileHeader* files = essential->header.files; if ((fvx_qread("I:/nand_hdr.bin", &(essential->nand_hdr), 0, 0x200, (UINT*) &(files[0].size)) != FR_OK) || @@ -73,34 +73,34 @@ u32 BuildEssentialBackup(const char* path, EssentialBackup* essential) { InitImgFS(path_bak); return 1; } - + // HWCAL0.dat / HWCAL1.dat if ((fvx_qread("7:/ro/sys/HWCAL0.dat", &(essential->hwcal0), 0, 0x1000, (UINT*) &(files[6].size)) != FR_OK) || (fvx_qread("7:/ro/sys/HWCAL1.dat", &(essential->hwcal1), 0, 0x1000, (UINT*) &(files[7].size)) != FR_OK)) { memset(&(filelist[6]), 0, 2 * sizeof(ExeFsFileHeader)); } - + // mount original file InitImgFS(path_bak); - + // fill nand cid / otp hash sdmmc_get_cid(1, (u32*) (void*) &(essential->nand_cid)); if (!IS_UNLOCKED) memset(&(filelist[5]), 0, 3 * sizeof(ExeFsFileHeader)); else memcpy(&(essential->otp), (u8*) __OTP_ADDR, 0x100); - + // calculate hashes - for (u32 i = 0; i < 8 && *(filelist[i].name); i++) + for (u32 i = 0; i < 8 && *(filelist[i].name); i++) sha_quick(essential->header.hashes[9-i], ((u8*) essential) + files[i].offset + sizeof(ExeFsHeader), files[i].size, SHA256_MODE); - + return 0; } u32 CheckEmbeddedBackup(const char* path) { EssentialBackup* essential = (EssentialBackup*) malloc(sizeof(EssentialBackup)); EssentialBackup* embedded = (EssentialBackup*) malloc(sizeof(EssentialBackup)); - + if (!essential || !embedded || (BuildEssentialBackup(path, essential) != 0) || (fvx_qread(path, embedded, SECTOR_D0K3 * 0x200, sizeof(EssentialBackup), NULL) != FR_OK) || (memcmp(embedded, essential, sizeof(EssentialBackup)) != 0)) { @@ -108,7 +108,7 @@ u32 CheckEmbeddedBackup(const char* path) { free(embedded); return 1; } - + free(essential); free(embedded); return 0; @@ -117,7 +117,7 @@ u32 CheckEmbeddedBackup(const char* path) { u32 EmbedEssentialBackup(const char* path) { EssentialBackup* essential = (EssentialBackup*) malloc(sizeof(EssentialBackup)); if (!essential) return 1; - + // leaving out the write permissions check here, it's okay if ((BuildEssentialBackup(path, essential) != 0) || (ValidateNandNcsdHeader((void*)essential->nand_hdr) != 0) || @@ -125,7 +125,7 @@ u32 EmbedEssentialBackup(const char* path) { free(essential); return 1; } - + free(essential); return 0; } @@ -133,27 +133,27 @@ u32 EmbedEssentialBackup(const char* path) { u32 DumpGbaVcSavegameBuffered(const char* path, void* buffer) { AgbSaveHeader* agbsave = (AgbSaveHeader*) buffer; u8* savegame = (u8*) (agbsave + 1); - + // read full AGBsave to memory if ((fvx_qread(path, agbsave, 0, sizeof(AgbSaveHeader), NULL) != FR_OK) || (ValidateAgbSaveHeader(agbsave) != 0) || (fvx_qread(path, savegame, sizeof(AgbSaveHeader), agbsave->save_size, NULL) != FR_OK)) return 1; // not a proper AGBSAVE file - + // byteswap for eeprom type saves (512 byte / 8 kB) if ((agbsave->save_size == GBASAVE_EEPROM_512) || (agbsave->save_size == GBASAVE_EEPROM_8K)) { for (u8* ptr = savegame; (ptr - savegame) < (int) agbsave->save_size; ptr += 8) *(u64*) (void*) ptr = getbe64(ptr); } - + // ensure the output dir exists if (fvx_rmkdir(OUTPUT_PATH) != FR_OK) return 1; - + // generate output path char path_vcsav[64]; snprintf(path_vcsav, 64, OUTPUT_PATH "/%016llX.gbavc.sav", agbsave->title_id); if (fvx_qwrite(path_vcsav, savegame, 0, agbsave->save_size, NULL) != FR_OK) return 1; // write fail - - return 0; + + return 0; } u32 DumpGbaVcSavegame(const char* path) { @@ -162,7 +162,7 @@ u32 DumpGbaVcSavegame(const char* path) { ShowPrompt(false, "Out of memory."); return 1; } - + u32 ret = DumpGbaVcSavegameBuffered(path, buffer); free(buffer); return ret; @@ -171,7 +171,7 @@ u32 DumpGbaVcSavegame(const char* path) { u32 InjectGbaVcSavegameBuffered(const char* path, const char* path_vcsave, void* buffer) { AgbSaveHeader* agbsave = (AgbSaveHeader*) buffer; u8* savegame = (u8*) (agbsave + 1); - + // basic sanity checks for path_vcsave FILINFO fno; char* ext = strrchr(path_vcsave, '.'); @@ -179,27 +179,27 @@ u32 InjectGbaVcSavegameBuffered(const char* path, const char* path_vcsave, void* (strncasecmp(ext+1, "SaveRAM", 8) != 0))) return 1; // bad extension if ((fvx_stat(path_vcsave, &fno) != FR_OK) || !GBASAVE_VALID(fno.fsize)) return 1; // bad size - + // read AGBsave header to memory if ((fvx_qread(path, agbsave, 0, sizeof(AgbSaveHeader), NULL) != FR_OK) || (ValidateAgbSaveHeader(agbsave) != 0)) return 1; // not a proper header - + // read savegame to memory u32 inject_save_size = min(agbsave->save_size, fno.fsize); memset(savegame, 0xFF, agbsave->save_size); // pad with 0xFF if (fvx_qread(path_vcsave, savegame, 0, inject_save_size, NULL) != FR_OK) return 1; - + // byteswap for eeprom type saves (512 byte / 8 kB) if ((agbsave->save_size == GBASAVE_EEPROM_512) || (agbsave->save_size == GBASAVE_EEPROM_8K)) { for (u8* ptr = savegame; (ptr - savegame) < (int) inject_save_size; ptr += 8) *(u64*) (void*) ptr = getbe64(ptr); } - + // fix CMAC for NAND partition, rewrite AGBSAVE file u32 data_size = sizeof(AgbSaveHeader) + agbsave->save_size; if (FixAgbSaveCmac(agbsave, NULL, NULL) != 0) return 1; if (fvx_qwrite(path, agbsave, 0, data_size, NULL) != FR_OK) return 1; // write fail - + // fix CMAC for SD partition, take it over to SD if (strncasecmp(path, "S:/agbsave.bin", 256) == 0) { AgbSaveHeader agbsave_sd; @@ -217,18 +217,18 @@ u32 InjectGbaVcSavegameBuffered(const char* path, const char* path_vcsave, void* (ValidateAgbSaveHeader(&agbsave_sd) == 0) && (agbsave->times_saved == agbsave_sd.times_saved)) slot = data_size; // proper slot is bottom slot (otherwise it's the top slot) - + // inject next slot agbsave->times_saved++; // increase # of times saved if (FixAgbSaveCmac(agbsave, NULL, path_sd) != 0) return 1; if (fvx_qwrite(path_sd, agbsave, slot, data_size, NULL) != FR_OK) return 1; // write fail } - + // set CFG_BOOTENV to 0x7 so the save is taken over (not needed anymore) // https://www.3dbrew.org/wiki/CONFIG9_Registers#CFG9_BOOTENV // if (strncasecmp(path, "S:/agbsave.bin", 256) == 0) *(u32*) 0x10010000 = 0x7; - - return 0; + + return 0; } u32 InjectGbaVcSavegame(const char* path, const char* path_vcsave) { @@ -237,7 +237,7 @@ u32 InjectGbaVcSavegame(const char* path, const char* path_vcsave) { ShowPrompt(false, "Out of memory."); return 1; } - + u32 ret = InjectGbaVcSavegameBuffered(path, path_vcsave, buffer); free(buffer); return ret; @@ -246,54 +246,54 @@ u32 InjectGbaVcSavegame(const char* path, const char* path_vcsave) { u32 RebuildNandNcsdHeader(NandNcsdHeader* ncsd) { // signature (retail or dev) const u8* signature = (IS_DEVKIT) ? sig_nand_ncsd_dev : sig_nand_ncsd_retail; - + // encrypted TWL MBR u8 twl_mbr_data[0x200] = { 0 }; u8* twl_mbr = twl_mbr_data + (0x200 - sizeof(twl_mbr_std)); memcpy(twl_mbr, twl_mbr_std, sizeof(twl_mbr_std)); CryptNand(twl_mbr_data, 0, 1, 0x03); - + // rebuild NAND header for console - memset(ncsd, 0x00, sizeof(NandNcsdHeader)); + memset(ncsd, 0x00, sizeof(NandNcsdHeader)); memcpy(ncsd->signature, signature, 0x100); // signature memcpy(ncsd->twl_mbr, twl_mbr, 0x42); // TWL MBR memcpy(ncsd->magic, "NCSD", 0x4); // magic number ncsd->size = (IS_O3DS) ? 0x200000 : 0x280000; // total size - + // TWL partition (0) ncsd->partitions_fs_type[0] = 0x01; ncsd->partitions_crypto_type[0] = 0x01; ncsd->partitions[0].offset = 0x000000; ncsd->partitions[0].size = 0x058800; - + // AGBSAVE partition (1) ncsd->partitions_fs_type[1] = 0x04; ncsd->partitions_crypto_type[1] = 0x02; ncsd->partitions[1].offset = 0x058800; ncsd->partitions[1].size = 0x000180; - + // FIRM0 partition (2) ncsd->partitions_fs_type[2] = 0x03; ncsd->partitions_crypto_type[2] = 0x02; ncsd->partitions[2].offset = 0x058980; ncsd->partitions[2].size = 0x002000; - + // FIRM1 partition (3) ncsd->partitions_fs_type[3] = 0x03; ncsd->partitions_crypto_type[3] = 0x02; ncsd->partitions[3].offset = 0x05A980; ncsd->partitions[3].size = 0x002000; - + // CTR partition (4) ncsd->partitions_fs_type[4] = 0x01; ncsd->partitions_crypto_type[4] = (IS_O3DS) ? 0x02 : 0x03; ncsd->partitions[4].offset = 0x05C980; ncsd->partitions[4].size = (IS_O3DS) ? 0x17AE80 : 0x20F680; - + // unknown stuff - whatever this is ¯\_(ツ)_/¯ ncsd->unknown[0x25] = 0x04; ncsd->unknown[0x2C] = 0x01; - + // done return 0; } @@ -301,13 +301,13 @@ u32 RebuildNandNcsdHeader(NandNcsdHeader* ncsd) { u32 FixNandHeader(const char* path, bool check_size) { NandNcsdHeader ncsd; if (RebuildNandNcsdHeader(&ncsd) != 0) return 1; - + // safety check FILINFO fno; FSIZE_t min_size = check_size ? GetNandNcsdMinSizeSectors(&ncsd) * 0x200 : 0x200; if ((fvx_stat(path, &fno) != FR_OK) || (min_size > fno.fsize)) return 1; - + // inject to path if (!CheckWritePermissions(path)) return 1; return (fvx_qwrite(path, &ncsd, 0x0, 0x200, NULL) == FR_OK) ? 0 : 1; @@ -316,15 +316,15 @@ u32 FixNandHeader(const char* path, bool check_size) { u32 ValidateNandDump(const char* path) { NandPartitionInfo info; FIL file; - + // truncated path string char pathstr[32 + 1]; TruncateString(pathstr, path, 32, 8); - + // open file if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; - + // check NAND header NandNcsdHeader ncsd; if ((ReadNandFile(&file, &ncsd, 0, 1, 0xFF) != 0) || (ValidateNandNcsdHeader(&ncsd) != 0)) { @@ -332,14 +332,14 @@ u32 ValidateNandDump(const char* path) { fvx_close(&file); return 1; } - + // check size if (fvx_size(&file) < (GetNandNcsdMinSizeSectors(&ncsd) * 0x200)) { ShowPrompt(false, "%s\nNAND dump misses data", pathstr); fvx_close(&file); return 1; } - + // check TWL & CTR FAT partitions for (u32 i = 0; i < 2; i++) { char* section_type = (i) ? "CTR" : "MBR"; @@ -366,11 +366,11 @@ u32 ValidateNandDump(const char* path) { } } } - + // check FIRMs (at least one FIRM must be valid) u8* firm = (u8*) malloc(FIRM_MAX_SIZE); if (!firm) return 1; - + // check all 8 firms, also check if ARM9 & ARM11 entrypoints are available for (u32 f = 0; f <= 8; f++) { if (GetNandNcsdPartitionInfo(&info, NP_TYPE_FIRM, NP_SUBTYPE_CTR, f, &ncsd) != 0) { @@ -379,17 +379,17 @@ u32 ValidateNandDump(const char* path) { free(firm); return 1; } - + u32 firm_size = info.count * 0x200; if ((firm_size <= FIRM_MAX_SIZE) && (ReadNandFile(&file, firm, info.sector, info.count, info.keyslot) == 0) && (ValidateFirm(firm, firm_size, true) == 0)) break; } - + free(firm); fvx_close(&file); - + return 0; } @@ -406,17 +406,17 @@ u32 SafeRestoreNandDump(const char* path) { EmbedEssentialBackup("S:/nand.bin"); else return 1; } - + if (!ShowUnlockSequence(5, "!WARNING!\n \nProceeding will overwrite the\nSysNAND with the provided dump.\n \n(B9S/A9LH will be left intact.)")) return 1; if (!SetWritePermissions(PERM_SYS_LVL1, true)) return 1; - + // open file, get size FIL file; if (fvx_open(&file, path, FA_READ | FA_OPEN_EXISTING) != FR_OK) return 1; u32 fsize = fvx_size(&file); - + // get NCSD headers from image and SysNAND NandNcsdHeader ncsd_loc, ncsd_img; MbrHeader twl_mbr_img; @@ -426,7 +426,7 @@ u32 SafeRestoreNandDump(const char* path) { fvx_close(&file); return 1; } - + // compare NCSD header partitioning // FIRMS must be at the same place for image and local NAND bool header_inject = false; @@ -452,7 +452,7 @@ u32 SafeRestoreNandDump(const char* path) { return 1; } } - + // additional warning for elevated write permissions if (header_inject) { if (!ShowPrompt(true, "!WARNING!\n \nNCSD differs between image and local,\nelevated write permissions required\n \nProceed on your own risk?") || @@ -461,13 +461,13 @@ u32 SafeRestoreNandDump(const char* path) { return 1; } } - + u8* buffer = (u8*) malloc(STD_BUFFER_SIZE); if (!buffer) { fvx_close(&file); return 1; } - + // main processing loop u32 ret = 0; u32 sector0 = SECTOR_SECRET + COUNT_SECRET; // start at the sector after secret sector @@ -487,22 +487,22 @@ u32 SafeRestoreNandDump(const char* path) { if (sector1 == fsize / 0x200) break; // at file end sector0 = np_info.sector + np_info.count; // skip partition } - + free(buffer); fvx_close(&file); - + // NCSD header inject, should only be required with 2.1 local NANDs on N3DS if (header_inject && (ret == 0) && (WriteNandSectors((u8*) &ncsd_img, 0, 1, 0xFF, NAND_SYSNAND) != 0)) ret = 1; - + return ret; } u32 SafeInstallFirmBuffered(const char* path, u32 slots, u8* buffer, u32 bufsiz) { char pathstr[32 + 1]; // truncated path string TruncateString(pathstr, path, 32, 8); - + // load / check FIRM u8* firm = buffer; UINT firm_size; @@ -512,12 +512,12 @@ u32 SafeInstallFirmBuffered(const char* path, u32 slots, u8* buffer, u32 bufsiz) "%s\nNot a installable FIRM." : "%s\nFIRM load/verify error.", pathstr); return 1; } - + // inject sighax signature, get hash u8 firm_sha[0x20]; memcpy(firm + 0x100, (IS_DEVKIT) ? sig_nand_firm_dev : sig_nand_firm_retail, 0x100); sha_quick(firm_sha, firm, firm_size, SHA256_MODE); - + // check install slots for (u32 s = 0; s < 8; s++) { NandPartitionInfo info; @@ -528,7 +528,7 @@ u32 SafeInstallFirmBuffered(const char* path, u32 slots, u8* buffer, u32 bufsiz) return 1; } } - + // check sector 0x96 on N3DS, offer fix if required u8 sector0x96[0x200] __attribute__((aligned(4))); bool fix_sector0x96 = false; @@ -552,11 +552,11 @@ u32 SafeInstallFirmBuffered(const char* path, u32 slots, u8* buffer, u32 bufsiz) fix_sector0x96 = true; } else return 1; } - + // all checked, ready to go if (!ShowUnlockSequence(6, "!WARNING!\n \nProceeding will install the\nprovided FIRM to the SysNAND\nand inject sighax.\n \nInstalling an unsupported FIRM\nwill BRICK your console!")) return 1; // if (!SetWritePermissions(PERM_SYS_LVL3, true)) return 1; // one unlock sequence is enough - + // point of no return ShowString(false, "Installing FIRM, please wait..."); if (fix_sector0x96 && (WriteNandSectors(sector0x96, 0x96, 1, 0x11, NAND_SYSNAND) != 0)) { @@ -572,7 +572,7 @@ u32 SafeInstallFirmBuffered(const char* path, u32 slots, u8* buffer, u32 bufsiz) return 1; } } - + // done, now check the installation ShowString(false, "Checking installation, please wait..."); if (fix_sector0x96 && ((ReadNandSectors(sector0x96, 0x96, 1, 0x11, NAND_SYSNAND) != 0) || @@ -590,7 +590,7 @@ u32 SafeInstallFirmBuffered(const char* path, u32 slots, u8* buffer, u32 bufsiz) return 1; } } - + return 0; } @@ -600,7 +600,7 @@ u32 SafeInstallFirm(const char* path, u32 slots) { ShowPrompt(false, "Out of memory."); return 1; } - + u32 ret = SafeInstallFirmBuffered(path, slots, buffer, FIRM_MAX_SIZE); free(buffer); return ret; @@ -609,29 +609,29 @@ u32 SafeInstallFirm(const char* path, u32 slots) { u32 SafeInstallKeyDb(const char* path) { static const u8 perfect_sha[] = { KEYDB_PERFECT_HASH }; u8 keydb[KEYDB_PERFECT_SIZE] __attribute__((aligned(4))); - + char pathstr[32 + 1]; // truncated path string TruncateString(pathstr, path, 32, 8); - + // already installed? if ((ReadNandBytes(keydb, SECTOR_KEYDB*0x200, KEYDB_PERFECT_SIZE, 0xFF, NAND_SYSNAND) == 0) && (sha_cmp(perfect_sha, keydb, KEYDB_PERFECT_SIZE, SHA256_MODE) == 0)) { ShowPrompt(false, "Perfect " KEYDB_NAME " is already installed!"); return 1; } - + // check input path... if ((fvx_qread(path, keydb, 0, KEYDB_PERFECT_SIZE, NULL) != FR_OK) || (sha_cmp(perfect_sha, keydb, KEYDB_PERFECT_SIZE, SHA256_MODE) != 0)) { ShowPrompt(false, "%s\nNot a perfect " KEYDB_NAME " image.\nCannot install to NAND!", pathstr); return 1; } - + // point of no return, install key database if (WriteNandBytes(keydb, SECTOR_KEYDB*0x200, KEYDB_PERFECT_SIZE, 0xFF, NAND_SYSNAND) != 0) { ShowPrompt(false, "%s\nFailed writing " KEYDB_NAME " to NAND!", pathstr); return 1; } - + return 0; } diff --git a/arm9/source/utils/paint9.c b/arm9/source/utils/paint9.c index 2f394f0..7bedd0c 100644 --- a/arm9/source/utils/paint9.c +++ b/arm9/source/utils/paint9.c @@ -81,7 +81,7 @@ void Paint9_DrawBrush(u16 px, u16 py, u32 color_fg, u32 color_bg, u32 id) { // https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm#C void Paint9_DrawLine(u16 px0, u16 py0, u16 px1, u16 py1, u32 color_fg, u32 id) { const int dx = abs((s16) px1-px0), sx = (px0 < px1) ? 1 : -1; - const int dy = abs((s16) py1-py0), sy = (py0 < py1) ? 1 : -1; + const int dy = abs((s16) py1-py0), sy = (py0 < py1) ? 1 : -1; int err = ((dx > dy) ? dx : -dy) / 2; while (true) { diff --git a/arm9/source/utils/scripting.c b/arm9/source/utils/scripting.c index 6bbf58c..6817ea0 100644 --- a/arm9/source/utils/scripting.c +++ b/arm9/source/utils/scripting.c @@ -232,7 +232,7 @@ static inline bool isntrboot(void) { static inline u32 strntohex(const char* str, u8* hex, u32 len) { if (!len) { - len = strlen(str); + len = strlen(str); if (len%1) return 0; else len >>= 1; } else if (len*2 != strnlen(str, (len*2)+1)) { @@ -285,28 +285,28 @@ static inline u32 line_len(const char* text, u32 len, u32 ww, const char* line, } static inline char* line_seek(const char* text, u32 len, u32 ww, const char* line, int add) { - // safety checks / + // safety checks / if (line < text) return NULL; if ((line >= (text + len)) && (add >= 0)) return (char*) line; - + if (!ww) { // non wordwrapped mode char* lf = ((char*) line - 1); - + // ensure we are at the start of the line while ((lf > text) && (*lf != '\n')) lf--; - + // handle backwards search for (; (add < 0) && (lf >= text); add++) for (lf--; (lf >= text) && (*lf != '\n'); lf--); - + // handle forwards search for (; (add > 0) && (lf < text + len); add--) for (lf++; (lf < text + len) && (*lf != '\n'); lf++); - + return lf + 1; } else { // wordwrapped mode char* l0 = (char*) line; - + // handle forwards wordwrapped search for (; (add > 0) && (l0 < text + len); add--) { char* eol = NULL; @@ -314,7 +314,7 @@ static inline char* line_seek(const char* text, u32 len, u32 ww, const char* lin if (eol || !llenww) l0 = line_seek(text, len, 0, l0, 1); else l0 += llenww; } - + // handle backwards wordwrapped search while ((add < 0) && (l0 > text)) { char* l1 = line_seek(text, len, 0, l0, -1); @@ -331,19 +331,19 @@ static inline char* line_seek(const char* text, u32 len, u32 ww, const char* lin } } - + return l0; } } static inline u32 get_lno(const char* text, u32 len, const char* line) { u32 lno = 1; - + for (u32 i = 0; i < len; i++) { if (line <= text + i) return lno; else if (text[i] == '\n') lno++; } - + return 0; } @@ -369,11 +369,11 @@ void set_preview(const char* name, const char* content) { char* set_var(const char* name, const char* content) { Gm9ScriptVar* vars = (Gm9ScriptVar*) var_buffer; - + if ((strnlen(name, _VAR_NAME_LEN) > (_VAR_NAME_LEN-1)) || (strnlen(content, _VAR_CNT_LEN) > (_VAR_CNT_LEN-1)) || (strchr(name, '[') || strchr(name, ']'))) return NULL; - + u32 n_var = 0; for (Gm9ScriptVar* var = vars; n_var < _VAR_MAX_BUFF; n_var++, var++) if (!*(var->name) || (strncmp(var->name, name, _VAR_NAME_LEN) == 0)) break; @@ -383,10 +383,10 @@ char* set_var(const char* name, const char* content) { strncpy(vars[n_var].content, content, _VAR_CNT_LEN); vars[n_var].content[_VAR_CNT_LEN - 1] = '\0'; if (!n_var) *(vars[n_var].content) = '\0'; // NULL var - + // update preview stuff set_preview(name, content); - + return vars[n_var].content; } @@ -397,18 +397,18 @@ void upd_var(const char* name) { u8 secinfo_data[1 + 1 + 16] = { 0 }; char* env_serial = (char*) secinfo_data + 2; char env_region[3 + 1] = { 0 }; - + snprintf(env_region, 0x4, "UNK"); if ((FileGetData("1:/rw/sys/SecureInfo_A", secinfo_data, 0x11, 0x100) != 0x11) && (FileGetData("1:/rw/sys/SecureInfo_B", secinfo_data, 0x11, 0x100) != 0x11)) snprintf(env_serial, 0xF, "UNKNOWN"); else if (*secinfo_data < SMDH_NUM_REGIONS) strncpy(env_region, g_regionNamesShort[*secinfo_data], countof(env_region) - 1); - + set_var("SERIAL", env_serial); set_var("REGION", env_region); } - + // device sysnand / emunand id0 for (u32 emu = 0; emu <= 1; emu++) { const char* env_id0_name = (emu) ? "EMUID0" : "SYSID0"; @@ -425,7 +425,7 @@ void upd_var(const char* name) { set_var(env_id0_name, env_id0); } } - + // datestamp & timestamp if (!name || (strncmp(name, "DATESTAMP", _VAR_NAME_LEN) == 0) || (strncmp(name, "TIMESTAMP", _VAR_NAME_LEN) == 0)) { DsTime dstime; @@ -449,7 +449,7 @@ void upd_var(const char* name) { char* get_var(const char* name, char** endptr) { Gm9ScriptVar* vars = (Gm9ScriptVar*) var_buffer; - + u32 name_len = 0; char* pname = NULL; if (!endptr) { // no endptr, varname is verbatim @@ -462,26 +462,26 @@ char* get_var(const char* name, char** endptr) { if ((name_len >= _VAR_NAME_LEN) || !pname[name_len]) return NULL; *endptr = pname + name_len + 1; } - + char vname[_VAR_NAME_LEN]; strncpy(vname, pname, name_len); vname[name_len] = '\0'; upd_var(vname); // handle dynamic env vars - + u32 n_var = 0; for (Gm9ScriptVar* var = vars; n_var < _VAR_MAX_BUFF; n_var++, var++) { if (!*(var->name) || (strncmp(var->name, vname, _VAR_NAME_LEN) == 0)) break; } - + if (n_var >= _VAR_MAX_BUFF || !*(vars[n_var].name)) n_var = 0; - + return vars[n_var].content; } bool init_vars(const char* path_script) { // reset var buffer memset(var_buffer, 0x00, sizeof(Gm9ScriptVar) * _VAR_MAX_BUFF); - + // current path char curr_dir[_VAR_CNT_LEN]; if (path_script) { @@ -490,9 +490,9 @@ bool init_vars(const char* path_script) { char* slash = strrchr(curr_dir, '/'); if (slash) *slash = '\0'; } else strncpy(curr_dir, "(null)", _VAR_CNT_LEN - 1); - + // set env vars - set_var("NULL", ""); // this one is special and should not be changed later + set_var("NULL", ""); // this one is special and should not be changed later set_var("CURRDIR", curr_dir); // script path, never changes set_var("GM9OUT", OUTPUT_PATH); // output path, never changes set_var("HAX", IS_UNLOCKED ? (isntrboot() ? "ntrboot" : "sighax") : ""); // type of hax running from @@ -501,17 +501,17 @@ bool init_vars(const char* path_script) { char* ptr = set_var("GM9VER", VERSION); // GodMode9 version, truncated below while (*(ptr++) != '\0') if (*ptr == '-') *ptr = '\0'; upd_var(NULL); // set all dynamic environment vars - + return true; } bool expand_arg(char* argex, const char* arg, u32 len) { char* out = argex; - + for (char* in = (char*) arg; in - arg < (int) len; in++) { u32 out_len = out - argex; if (out_len >= (_ARG_MAX_LEN-1)) return false; // maximum arglen reached - + if (*in == '\\') { // escape line breaks if (*(++in) == 'n') *(out++) = '\n'; else { @@ -529,20 +529,20 @@ bool expand_arg(char* argex, const char* arg, u32 len) { } else *(out++) = *in; } *out = '\0'; - + return true; } cmd_id get_cmd_id(char* cmd, u32 len, u32 flags, u32 argc, char* err_str) { const Gm9ScriptCmd* cmd_entry = NULL; - + for (u32 i = 0; i < (sizeof(cmd_list)/sizeof(Gm9ScriptCmd)); i++) { if (strncmp(cmd_list[i].cmd, cmd, len) == 0) { cmd_entry = cmd_list + i; break; } } - + if (!cmd_entry) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "unknown cmd"); } else if (cmd_entry->n_args != argc) { @@ -550,13 +550,13 @@ cmd_id get_cmd_id(char* cmd, u32 len, u32 flags, u32 argc, char* err_str) { } else if (~(cmd_entry->allowed_flags|_FLG('o')|_FLG('s')) & flags) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "unrecognized flags"); } else return cmd_entry->id; - + return CMD_ID_NONE; } u32 get_flag(char* str, u32 len, char* err_str) { char flag_char = '\0'; - + if ((len < 2) || (*str != '-')) flag_char = '\0'; else if (len == 2) flag_char = str[1]; else if (strncmp(str, "--all", len) == 0) flag_char = 'a'; @@ -577,23 +577,23 @@ u32 get_flag(char* str, u32 len, char* err_str) { else if (strncmp(str, "--unequal", len) == 0) flag_char = 'u'; else if (strncmp(str, "--overwrite", len) == 0) flag_char = 'w'; else if (strncmp(str, "--explorer", len) == 0) flag_char = 'x'; - + if ((flag_char < 'a') && (flag_char > 'z')) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "illegal flag"); return 0; } - + return _FLG(flag_char); } char* get_string(char* ptr, const char* line_end, u32* len, char** next, char* err_str) { char* str = NULL; *len = 0; - + // skip whitespaces for (; IS_WHITESPACE(*ptr) && (ptr < line_end); ptr++); if (ptr >= line_end) return (*next = (char*) line_end); // end reached, all whitespaces - + // handle string if (*ptr == '\"') { // quotes str = ++ptr; @@ -604,11 +604,11 @@ char* get_string(char* ptr, const char* line_end, u32* len, char** next, char* e } *next = ptr + 1; } else { // no quotes, no whitespace - str = ptr; + str = ptr; for (; !IS_WHITESPACE(*ptr) && (ptr < line_end); ptr++, (*len)++); *next = ptr; } - + return str; } @@ -618,16 +618,16 @@ char* skip_block(char* ptr, bool ignore_else, bool stop_after_end) { char* line_start = ptr; char* line_end = strchr(ptr, '\n'); if (!line_end) line_end = ptr + strlen(ptr); - + // grab first string char* str = NULL; u32 str_len = 0; if (!(str = get_string(ptr, line_end, &str_len, &ptr, NULL)) || (str >= line_end)) { // string error or empty line ptr = line_end + 1; - continue; + continue; } - + // check string if (MATCH_STR(str, str_len, _CMD_END)) { // stop at end return line_start; // end of block found @@ -638,19 +638,19 @@ char* skip_block(char* ptr, bool ignore_else, bool stop_after_end) { } else if (MATCH_STR(str, str_len, _CMD_IF)) { ptr = line_start = skip_block(line_end + 1, true, false); if (ptr == NULL) return NULL; - + line_end = strchr(ptr, '\n'); if (!line_end) line_end = ptr + strlen(ptr); - + str = get_string(ptr, line_end, &str_len, &ptr, NULL); if (!(MATCH_STR(str, str_len, _CMD_END))) return NULL; if (stop_after_end) return line_end + 1; } - + // move on to the next line ptr = line_end + 1; } - + // end of block not found return NULL; } @@ -661,16 +661,16 @@ char* find_next(char* ptr) { char* line_start = ptr; char* line_end = strchr(ptr, '\n'); if (!line_end) line_end = ptr + strlen(ptr); - + // grab first string char* str = NULL; u32 str_len = 0; if (!(str = get_string(ptr, line_end, &str_len, &ptr, NULL)) || (str >= line_end)) { // string error or empty line ptr = line_end + 1; - continue; + continue; } - + // check string if (MATCH_STR(str, str_len, _CMD_IF)) { // skip 'if' blocks ptr = skip_block(ptr, true, true); @@ -679,11 +679,11 @@ char* find_next(char* ptr) { } else if (MATCH_STR(str, str_len, _CMD_NEXT)) { return line_start; } - + // move on to the next line ptr = line_end + 1; } - + // 'next' not found return NULL; } @@ -692,13 +692,13 @@ char* find_label(const char* label, const char* last_found) { char* script = (char*) script_buffer; char* ptr = script; u32 label_len = strnlen(label, _ARG_MAX_LEN); - + if (last_found) { ptr = strchr(last_found, '\n'); if (!ptr) return NULL; ptr++; } - + char* next = ptr; for (; next && *ptr; ptr = next) { // store line start / get line end @@ -706,27 +706,27 @@ char* find_label(const char* label, const char* last_found) { char* line_end = strchr(ptr, '\n'); if (!line_end) line_end = ptr + strlen(ptr); next = line_end + 1; - + // search for label char* str = NULL; u32 str_len = 0; if (!(str = get_string(ptr, line_end, &str_len, &ptr, NULL))) continue; // string error, ignore line else if (str >= line_end) continue; // empty line - + if (*str == '@') { // label found str++; str_len--; - + // compare it manually (also check for '*' at end) u32 pdiff = 0; for (; (pdiff < str_len) && (label[pdiff] == str[pdiff]); pdiff++); if ((pdiff < label_len) && (label[pdiff] != '*')) continue; // no match // otherwise: potential regular or wildcard match - + // may be a match, see if there are more strings after it if (!(str = get_string(ptr, line_end, &str_len, &ptr, NULL))) continue; // string error, ignore line else if ((str < line_end) && (*str != '#')) continue; // neither end of line nor comment - + return line_start; // match found } else if (MATCH_STR(str, str_len, _CMD_IF)) { next = skip_block(line_start, true, true); @@ -734,7 +734,7 @@ char* find_label(const char* label, const char* last_found) { next = find_next(line_start); } // otherwise: irrelevant line } - + return NULL; } @@ -744,13 +744,13 @@ bool for_handler(char* path, const char* dir, const char* pattern, bool recursiv static char ldir[256]; static char lpattern[64]; static bool rec = false; - + if (!path && !dir && !pattern) { // close all dirs while (dp >= fdir) fvx_closedir(dp--); dp = NULL; return true; } - + if (dir) { // open a dir snprintf(lpattern, 64, "%s", pattern); snprintf(ldir, 256, "%s", dir); @@ -769,14 +769,14 @@ bool for_handler(char* path, const char* dir, const char* pattern, bool recursiv if (!slash) return false; *slash = '\0'; } - + snprintf(path, 256, "%s/%.254s", ldir, fno.fname); if (rec && (fno.fattrib & AM_DIR) && (dp - fdir < _MAX_FOR_DEPTH - 1)) { if (fvx_opendir(++dp, path) != FR_OK) dp--; else strncpy(ldir, path, 255); } } else return false; - + return true; } @@ -784,18 +784,18 @@ bool parse_line(const char* line_start, const char* line_end, cmd_id* cmdid, u32 char* ptr = (char*) line_start; char* str; u32 len; - + // set everything to initial values *cmdid = 0; *flags = 0; *argc = 0; - + // search for cmd char* cmd = NULL; u32 cmd_len = 0; if (!(cmd = get_string(ptr, line_end, &cmd_len, &ptr, err_str))) return false; // string error if ((cmd >= line_end) || (*cmd == '#') || (*cmd == '@')) return true; // empty line or comment or label - + // special handling for "if", "elif" and "not" if (MATCH_STR(cmd, cmd_len, _CMD_NOT)) { *cmdid = CMD_ID_NOT; @@ -807,7 +807,7 @@ bool parse_line(const char* line_start, const char* line_end, cmd_id* cmdid, u32 *cmdid = CMD_ID_ELIF; return true; } - + // got cmd, now parse flags & args while ((str = get_string(ptr, line_end, &len, &ptr, err_str))) { bool in_quotes = ((ptr - str) != (int) len); // hacky @@ -825,14 +825,14 @@ bool parse_line(const char* line_start, const char* line_end, cmd_id* cmdid, u32 return false; // arg expand failed } } - + // end reached with a failed get_string() return false; } bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { bool ret = true; // true unless some cmd messes up - + // process arg0 @string u64 at_org = 0; u64 sz_org = 0; @@ -846,7 +846,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { } } } - + // perform command if (id == CMD_ID_NOT) { // check the argument @@ -859,7 +859,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { // "if true" or "if false" skip_state = (strncmp(argv[0], _ARG_TRUE, _ARG_MAX_LEN) == 0) ? 0 : _SKIP_BLOCK; ifcnt++; - + if (syntax_error && err_str) snprintf(err_str, _ERR_STR_LEN, "syntax error after 'if'"); ret = !syntax_error; @@ -871,12 +871,12 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { syntax_error = true; return false; } - + // skip state handling, check the argument if required // "if true" or "if false" skip_state = !skip_state ? _SKIP_TILL_END : ((strncmp(argv[0], _ARG_TRUE, _ARG_MAX_LEN) == 0) ? 0 : _SKIP_BLOCK); - + if (syntax_error && err_str) snprintf(err_str, _ERR_STR_LEN, "syntax error after 'elif'"); ret = !syntax_error; @@ -888,10 +888,10 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { syntax_error = true; return false; } - + // turn the skip state skip_state = skip_state ? 0 : _SKIP_TILL_END; - + ret = true; } else if (id == CMD_ID_END) { @@ -901,11 +901,11 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { syntax_error = true; return false; } - + // close last "if" skip_state = 0; ifcnt--; - + ret = true; } else if (id == CMD_ID_FOR) { @@ -959,16 +959,16 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { char* options_jmp[_CHOICE_MAX_N] = { NULL }; char options_str[_CHOICE_MAX_N][_CHOICE_STR_LEN+1]; u32 options_keys[_CHOICE_MAX_N] = { 0 }; - + char* ast = strchr(argv[1], '*'); char* ptr = NULL; u32 n_opt = 0; while ((ptr = find_label(argv[1], ptr))) { options_jmp[n_opt] = ptr; - + while (*(ptr++) != '@'); if (ast) ptr += (ast - argv[1]); - + char* choice = options_str[n_opt]; for (u32 i = 0; i < _CHOICE_STR_LEN; choice[++i] = '\0') { if (IS_WHITESPACE(ptr[i])) break; @@ -980,13 +980,13 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { for (; *choice != ' ' && *choice != '\0'; choice++); if (*choice != '\0') *(choice++) = '\0'; options_keys[n_opt] = StringToButton(keystr); - if (!options_keys[n_opt]) continue; + if (!options_keys[n_opt]) continue; } options[n_opt] = choice; if (++n_opt >= _CHOICE_MAX_N) break; } - + u32 result = (flags & _FLG('k')) ? ShowHotkeyPrompt(n_opt, options, options_keys, "%s", argv[0]) : ShowSelectPrompt(n_opt, options, "%s", argv[0]); @@ -1039,7 +1039,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { char* var = get_var(argv[2], NULL); strncpy(choice, var, _VAR_CNT_LEN); choice[_VAR_CNT_LEN - 1] = '\0'; - + char path[_VAR_CNT_LEN]; strncpy(path, argv[1], _VAR_CNT_LEN); path[_VAR_CNT_LEN - 1] = '\0'; @@ -1061,7 +1061,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { ret = FileSelector(choice, argv[0], path, NULL, NO_FILES | SELECT_DIRS, (flags & _FLG('x'))); if (err_str) snprintf(err_str, _ERR_STR_LEN, "dirselect abort"); } - + if (ret) { ret = set_var(argv[2], choice); if (err_str) snprintf(err_str, _ERR_STR_LEN, "var fail"); @@ -1075,14 +1075,14 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { char str[_ARG_MAX_LEN]; strncpy(str, argv[1], _ARG_MAX_LEN); str[_ARG_MAX_LEN - 1] = '\0'; - + ret = false; if (strlen(argv[2]) == 1) { // argv[2] must be one char char* found; if (flags & _FLG('f')) found = strchr(str, *argv[2]); else found = strrchr(str, *argv[2]); if (!found && err_str) snprintf(err_str, _ERR_STR_LEN, "char not found"); - + if (found) { if (flags & _FLG('b')) { *found = '\0'; @@ -1096,7 +1096,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { char str[_ARG_MAX_LEN]; strncpy(str, argv[1], _ARG_MAX_LEN); str[_ARG_MAX_LEN - 1] = '\0'; - + if (strnlen(argv[2], _ARG_MAX_LEN) != 2) { if (err_str) snprintf(err_str, _ERR_STR_LEN, "argv[2] must be 2 chars"); ret = false; @@ -1480,7 +1480,7 @@ bool run_cmd(cmd_id id, u32 flags, char** argv, char* err_str) { ret = false; if (err_str) snprintf(err_str, _ERR_STR_LEN, "unknown error"); } - + if (ret && err_str) snprintf(err_str, _ERR_STR_LEN, "command success"); return ret; } @@ -1494,18 +1494,18 @@ bool run_line(const char* line_start, const char* line_end, u32* flags, char* er // set up argv array for (u32 i = 0; i < _MAX_ARGS; i++) argv[i] = args[i]; - + // flags handling (if no pointer given) u32 lflags; if (!flags) flags = &lflags; *flags = 0; - + // parse current line, grab cmd / flags / args if (!parse_line(line_start, line_end, &cmdid, flags, &argc, argv, err_str)) { syntax_error = true; return false; } - + // control flow command handling // block out of control flow commands if (if_cond && IS_CTRLFLOW_CMD(cmdid)) { @@ -1513,36 +1513,36 @@ bool run_line(const char* line_start, const char* line_end, u32* flags, char* er syntax_error = true; return false; } - + // shortcuts for "elif" / "else" if (((cmdid == CMD_ID_ELIF) || (cmdid == CMD_ID_ELSE)) && !skip_state) { skip_state = _SKIP_TILL_END; cmdid = 0; } - + // handle "if" / "elif" / "not" if ((cmdid == CMD_ID_IF) || (cmdid == CMD_ID_ELIF) || (cmdid == CMD_ID_NOT)) { // set defaults argc = 1; strncpy(argv[0], _ARG_FALSE, _ARG_MAX_LEN - 1); - + // skip to behind the command char* line_start_next = (char*) line_start; for (; IS_WHITESPACE(*line_start_next); line_start_next++); for (; *line_start_next && !IS_WHITESPACE(*line_start_next); line_start_next++); - + // run condition, take over result if (run_line(line_start_next, line_end, flags, err_str, true)) strncpy(argv[0], _ARG_TRUE, _ARG_MAX_LEN - 1); } - + // run the command (if available) if (cmdid && !run_cmd(cmdid, *flags, argv, err_str)) { char* msg_fail = get_var("ERRORMSG", NULL); if (msg_fail && *msg_fail) *err_str = '\0'; // use custom error message return false; } - + // success if we arrive here return true; } @@ -1581,7 +1581,7 @@ void MemTextView(const char* text, u32 len, char* line0, int off_disp, int lno, if (ncpy > TV_LLEN_DISP) ncpy = TV_LLEN_DISP; bool al = !ww && off_disp && (ptr != ptr_next); bool ar = !ww && (llen > off_disp + TV_LLEN_DISP); - + // set text color / find start of comment of scripts u32 color_text = (nln == mno) ? script_color_active : (is_script) ? script_color_code : (u32) COLOR_TVTEXT; int cmt_start = TV_LLEN_DISP; // start of comment in current displayed line (may be negative) @@ -1591,14 +1591,14 @@ void MemTextView(const char* text, u32 len, char* line0, int off_disp, int lno, cmt_start = (hash - ptr) - off_disp; } if (cmt_start <= 0) color_text = script_color_comment; - + // build text string snprintf(txtstr, TV_LLEN_DISP + 1, "%-*.*s", (int) TV_LLEN_DISP, (int) TV_LLEN_DISP, ""); if (ncpy) memcpy(txtstr, ptr + off_disp, ncpy); for (char* d = txtstr; *d; d++) if (*d < ' ') *d = ' '; if (al) memcpy(txtstr + p_al, al_str, strnlen(al_str, 16)); if (ar) memcpy(txtstr + p_ar, ar_str, strnlen(ar_str, 16)); - + // draw line number & text DrawString(TOP_SCREEN, txtstr, x_txt, y, color_text, COLOR_STD_BG, false); if (TV_LNOS > 0) { // line number @@ -1606,17 +1606,17 @@ void MemTextView(const char* text, u32 len, char* line0, int off_disp, int lno, DrawStringF(TOP_SCREEN, x_lno, y, ((ptr == text) || (*(ptr-1) == '\n')) ? COLOR_TVOFFS : COLOR_TVOFFSL, COLOR_STD_BG, "%0*lu", TV_LNOS, nln); else DrawStringF(TOP_SCREEN, x_lno, y, COLOR_TVOFFSL, COLOR_STD_BG, "%*.*s", TV_LNOS, TV_LNOS, " "); } - + // colorize comment if is_script if ((cmt_start > 0) && ((u32) cmt_start < TV_LLEN_DISP)) { memset(txtstr, ' ', cmt_start); DrawString(TOP_SCREEN, txtstr, x_txt, y, script_color_comment, COLOR_TRANSPARENT, false); } - + // colorize arrows if (al) DrawStringF(TOP_SCREEN, x_al, y, COLOR_TVOFFS, COLOR_TRANSPARENT, al_str); if (ar) DrawStringF(TOP_SCREEN, x_ar, y, COLOR_TVOFFS, COLOR_TRANSPARENT, ar_str); - + // advance pointer / line number for (char* c = ptr; c < ptr_next; c++) if (*c == '\n') ++nln; ptr = ptr_next; @@ -1664,7 +1664,7 @@ bool MemTextViewer(const char* text, u32 len, u32 start, bool as_script) { while (true) { // display text on screen MemTextView(text, len, line0, off_disp, lcurr, ww, 0, as_script); - + // handle user input u32 pad_state = InputWait(0); char* line0_next = line0; @@ -1683,7 +1683,7 @@ bool MemTextViewer(const char* text, u32 len, u32 start, bool as_script) { ww = ww ? 0 : TV_LLEN_DISP; line0_next = line_seek(text, len, ww, line0, 0); } else if (pad_state & (BUTTON_B|BUTTON_START)) break; - + // check for problems, apply changes if (!ww && (line0_next > llast_nww)) line0_next = llast_nww; else if (ww && (line0_next > llast_ww)) line0_next = llast_ww; @@ -1697,10 +1697,10 @@ bool MemTextViewer(const char* text, u32 len, u32 start, bool as_script) { if (off_disp + TV_LLEN_DISP > llen_max) off_disp = llen_max - TV_LLEN_DISP; if ((off_disp < 0) || ww) off_disp = 0; } - + // clear screens ClearScreenF(true, true, COLOR_STD_BG); - + return true; } @@ -1711,17 +1711,17 @@ bool MemToCViewer(const char* text, u32 len, const char* title) { char* captions[max_captions]; u32 lineno[max_captions]; u32 ww = TV_LLEN_DISP; - + // check if this really is text if (!ValidateText(text, len)) { ShowPrompt(false, "Error: Invalid text data"); return false; } - + // clear screens / view start of readme on top ClearScreenF(true, true, COLOR_STD_BG); MemTextView(text, len, (char*) text, 0, 1, ww, 0, false); - + // parse text for markdown captions u32 n_captions = 0; char* ptr = (char*) text; @@ -1735,7 +1735,7 @@ bool MemToCViewer(const char* text, u32 len, const char* title) { } ptr = ptr_next; } - + int cursor = -1; while (true) { // display ToC @@ -1756,7 +1756,7 @@ bool MemToCViewer(const char* text, u32 len, const char* title) { "%*.*s", len, len, caption); y0 += FONT_HEIGHT_EXT + (2*TV_VPAD); } - + // handle user input u32 pad_state = InputWait(0); if ((cursor >= 0) && (pad_state & BUTTON_A)) { @@ -1772,10 +1772,10 @@ bool MemToCViewer(const char* text, u32 len, const char* title) { MemTextView(text, len, captions[cursor], 0, lineno[cursor], ww, 0, false); } } - + // clear screens ClearScreenF(true, true, COLOR_STD_BG); - + return true; } @@ -1802,29 +1802,29 @@ bool FileTextViewer(const char* path, bool as_script) { bool ExecuteGM9Script(const char* path_script) { char path_str[32+1]; TruncateString(path_str, path_script, 32, 12); - - + + // reset control flow global vars ifcnt = 0; jump_ptr = NULL; for_ptr = NULL; skip_state = 0; syntax_error = false; - - + + // allocate && check memory var_buffer = (void*) malloc(sizeof(Gm9ScriptVar) * _VAR_MAX_BUFF); script_buffer = (void*) malloc(SCRIPT_MAX_SIZE); char* script = (char*) script_buffer; char* ptr = script; - + if (!var_buffer || !script_buffer) { if (var_buffer) free(var_buffer); if (script_buffer) free(script_buffer); ShowPrompt(false, "Out of memory."); return false; } - + // fetch script from path u32 script_size = FileGetData(path_script, (u8*) script, SCRIPT_MAX_SIZE, 0); if (!script_size || (script_size >= SCRIPT_MAX_SIZE)) { @@ -1832,13 +1832,13 @@ bool ExecuteGM9Script(const char* path_script) { free(script_buffer); return false; } - + char* end = script + script_size; *end = '\0'; - + // initialise variables init_vars(path_script); - + // setup script preview (only if used) u32 preview_mode_local = 0; if (MAIN_SCREEN != TOP_SCREEN) { @@ -1848,7 +1848,7 @@ bool ExecuteGM9Script(const char* path_script) { script_color_comment = COLOR_TVCMT; script_color_code = COLOR_TVCMD; } - + // script execute loop u32 lno = 1; bool result = true; @@ -1905,17 +1905,17 @@ bool ExecuteGM9Script(const char* path_script) { MemTextView(script, script_size, script, 0, 1, 0, lno, true); } else { char* ptr_view = line_seek(script, script_size, 0, ptr, -(TV_NLIN_DISP/2)); - u32 lno_view = lno - (TV_NLIN_DISP/2); + u32 lno_view = lno - (TV_NLIN_DISP/2); MemTextView(script, script_size, ptr_view, 0, lno_view, 0, lno, true); } } } - + // run command char err_str[_ERR_STR_LEN+1] = { 0 }; result = run_line(ptr, line_end, &flags, err_str, false); - - + + // skip state handling char* skip_ptr = ptr; if ((skip_state == _SKIP_BLOCK) || (skip_state == _SKIP_TILL_END)) { @@ -1942,12 +1942,12 @@ bool ExecuteGM9Script(const char* path_script) { } skip_state = 0; } - - + + if (!result) { // error handling if (syntax_error) // severe error, can't continue flags &= ~(_FLG('o')|_FLG('s')); // never silent or optional - + if (!(flags & _FLG('s'))) { // not silent if (!*err_str) { char* msg_fail = get_var("ERRORMSG", NULL); @@ -1970,7 +1970,7 @@ bool ExecuteGM9Script(const char* path_script) { break; } else result = true; // set back the result otherwise } - + // reposition pointer if (skip_ptr != ptr) { ptr = skip_ptr; @@ -1987,8 +1987,8 @@ bool ExecuteGM9Script(const char* path_script) { lno++; } } - - + + if (result) { // all fine(?) up to this point if (ifcnt) { // check for unresolved 'if' ShowPrompt(false, "%s\nend of script: unresolved 'if'", path_str); @@ -2000,13 +2000,13 @@ bool ExecuteGM9Script(const char* path_script) { result = false; } } - + if (result) { // success message if applicable char* msg_okay = get_var("SUCCESSMSG", NULL); if (msg_okay && *msg_okay) ShowPrompt(false, "%s", msg_okay); } - - + + free(var_buffer); free(script_buffer); return result; diff --git a/arm9/source/utils/sysinfo.c b/arm9/source/utils/sysinfo.c index 47094a3..426f7c1 100644 --- a/arm9/source/utils/sysinfo.c +++ b/arm9/source/utils/sysinfo.c @@ -276,16 +276,16 @@ void GetSysInfo_Movable(SysInfo* info, char nand_drive) { strncpy(info->friendcodeseed, "", countof("")); strncpy(info->movablekeyy, "", countof("")); strncpy(info->nand_id0, "", countof("")); - + if (fvx_qread(path, &data, 0, 0x120 /* sizeof(data) */, NULL) != FR_OK) // whatever, we don't need the last 0x20 byte here return; - + // The LocalFriendCodeSeed. snprintf(info->friendcodeseed, 16 + 1, "%016llX", getbe64(data.codeseed_data.codeseed)); - + // The Movable KeyY snprintf(info->movablekeyy, 32 + 1, "%s%016llX", info->friendcodeseed, getbe64(data.keyy_high)); - + // SysNAND ID0 unsigned int sha256sum[8]; sha_quick(sha256sum, data.codeseed_data.codeseed, 16, SHA256_MODE); @@ -296,17 +296,17 @@ void GetSysInfo_Movable(SysInfo* info, char nand_drive) { // Read sdmmc. void GetSysInfo_SDMMC(SysInfo* info, char nand_drive) { (void) nand_drive; - + u8 nand_cid[16] = { 0 }; u8 sd_cid[16] = { 0 }; - + strncpy(info->nand_cid, "", countof("")); strncpy(info->sd_cid, "", countof("")); strncpy(info->nand_id1, "", countof("")); - + sdmmc_get_cid(1, (u32*) (void*) nand_cid); snprintf(info->nand_cid, 32 + 1, "%016llX%016llX", getbe64(nand_cid), getbe64(nand_cid+8)); - + sdmmc_get_cid(0, (u32*) (void*) sd_cid); snprintf(info->sd_cid, 32 + 1, "%016llX%016llX", getbe64(sd_cid), getbe64(sd_cid+8)); snprintf(info->nand_id1, 32 + 1, "%08lX%08lX%08lX%08lX", diff --git a/arm9/source/virtual/vbdri.c b/arm9/source/virtual/vbdri.c index 383af59..6d22001 100644 --- a/arm9/source/virtual/vbdri.c +++ b/arm9/source/virtual/vbdri.c @@ -90,9 +90,9 @@ u64 InitVBDRIDrive(void) { // prerequisite: .db file mounted as virtual diff ima u64 mount_state = CheckVDisaDiffDrive(); if (!(mount_state & SYS_DIFF)) return 0; is_tickdb = (mount_state & SYS_TICKDB); - + DeinitVBDRIDrive(); - + num_entries = min((is_tickdb ? GetNumTickets(PART_PATH) : GetNumTitleInfoEntries(PART_PATH)) + 1, VBDRI_MAX_ENTRIES); title_ids = (u8*) malloc(num_entries * 8); if (!title_ids || @@ -100,12 +100,12 @@ u64 InitVBDRIDrive(void) { // prerequisite: .db file mounted as virtual diff ima DeinitVBDRIDrive(); return 0; } - + if (!is_tickdb && ((cached_entry = malloc(sizeof(TitleInfoEntry))) == NULL)) { DeinitVBDRIDrive(); return 0; } - + return mount_state; } @@ -122,25 +122,25 @@ bool ReadVBDRIDir(VirtualFile* vfile, VirtualDir* vdir) { if (vdir->flags & VFLAG_TICKDIR) { // ticket dir if (!is_tickdb || (!tick_info && !SortVBDRITickets())) return false; - + while (++vdir->index < (int) num_entries) { u32 type = tick_info[vdir->index].type; u64 tid = getbe64(title_ids + (vdir->index * 8)); - - if ((tid == 0) || !( + + if ((tid == 0) || !( ((vdir->flags & VFLAG_ESHOP) && (type == 0)) || ((vdir->flags & VFLAG_HOMEBREW) && (type == 1)) || ((vdir->flags & VFLAG_SYSTEM) && (type == 2)) || ((vdir->flags & VFLAG_UNKNOWN) && (type == 3)))) continue; - + memset(vfile, 0, sizeof(VirtualFile)); snprintf(vfile->name, 32, NAME_TIK, tid, getle32(tick_info[vdir->index].console_id)); vfile->offset = vdir->index; // "offset" is the internal buffer index vfile->size = tick_info[vdir->index].size; vfile->keyslot = 0xFF; vfile->flags = (vdir->flags | VFLAG_DELETABLE) & ~VFLAG_DIR; - + return true; // found } } else { // root dir @@ -163,17 +163,17 @@ bool ReadVBDRIDir(VirtualFile* vfile, VirtualDir* vdir) { vfile->size = sizeof(TitleInfoEntry); vfile->keyslot = 0xFF; vfile->flags = (vdir->flags | VFLAG_DELETABLE) & ~VFLAG_DIR; - + return true; } } } - + return false; } bool GetNewVBDRIFile(VirtualFile* vfile, VirtualDir* vdir, const char* path) { - + size_t path_len = strlen(path), buf_len = (is_tickdb ? NAME_TIK_LEN : NAME_TIE_LEN) + 2; u64 tid; u32 console_id; @@ -181,8 +181,8 @@ bool GetNewVBDRIFile(VirtualFile* vfile, VirtualDir* vdir, const char* path) { char buf[buf_len]; strcpy(buf, path + path_len - buf_len + 1); - - + + if (( is_tickdb && (sscanf(buf, "/" NAME_TIK "%c", &tid, &console_id, &c) != 2)) || (!is_tickdb && (sscanf(buf, "/" NAME_TIE "%c", &tid, &c) != 1)) || (tid == 0)) @@ -193,15 +193,15 @@ bool GetNewVBDRIFile(VirtualFile* vfile, VirtualDir* vdir, const char* path) { for (u32 i = 0; i < num_entries; i++) { if ((entry_index == -1) && (*((u64*)(void*)(title_ids + 8 * i)) == 0)) entry_index = i; - + if (memcmp(&tid, title_ids + 8 * i, 8) == 0) return false; } - + if (entry_index == -1) { if (num_entries == VBDRI_MAX_ENTRIES) return false; - + u32 new_num_entries = min(num_entries + 128, VBDRI_MAX_ENTRIES); u8* new_title_ids = realloc(title_ids, new_num_entries * 8); if (!new_title_ids) @@ -212,37 +212,37 @@ bool GetNewVBDRIFile(VirtualFile* vfile, VirtualDir* vdir, const char* path) { return false; tick_info = new_tick_info; } - + entry_index = num_entries; num_entries = new_num_entries; title_ids = new_title_ids; - + memset(title_ids + entry_index * 8, 0, (num_entries - entry_index) * 8); } - + u32 size = is_tickdb ? TICKET_COMMON_SIZE : sizeof(TitleInfoEntry); u8 entry[size]; if (is_tickdb) *((u32*)(void*)(entry + 0x2A8)) = 0xAC000000; - if ((is_tickdb ? AddTicketToDB(PART_PATH, (u8*)&tid, (Ticket*)(void*)entry, false) : + if ((is_tickdb ? AddTicketToDB(PART_PATH, (u8*)&tid, (Ticket*)(void*)entry, false) : AddTitleInfoEntryToDB(PART_PATH, (u8*)&tid, (TitleInfoEntry*)(void*)entry, false)) != 0) return false; - + memcpy(title_ids + entry_index * 8, &tid, 8); - + if (tick_info) { tick_info[entry_index].type = 3; tick_info[entry_index].size = TICKET_COMMON_SIZE; memset(tick_info[entry_index].console_id, 0, 4); } - + memset(vfile, 0, sizeof(VirtualFile)); strcpy(vfile->name, buf); vfile->offset = entry_index; // "offset" is the internal buffer index vfile->size = size; vfile->keyslot = 0xFF; vfile->flags = (vdir->flags | VFLAG_DELETABLE) & ~VFLAG_DIR; - + return true; } @@ -251,14 +251,14 @@ int ReadVBDRIFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) memcpy(buffer, cached_entry + offset, count); return 0; } - + if (is_tickdb && (cache_index != -1)) free(cached_entry); if ((is_tickdb ? ReadTicketFromDB(PART_PATH, title_ids + vfile->offset * 8, (Ticket**) &cached_entry) : ReadTitleInfoEntryFromDB(PART_PATH, title_ids + vfile->offset * 8, (TitleInfoEntry*) cached_entry)) != 0) return 1; cache_index = (int) vfile->offset; - + memcpy(buffer, cached_entry + offset, count); return 0; } @@ -281,25 +281,25 @@ int WriteVBDRIFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 count return 1; } cache_index = (int) vfile->offset; - + if (resize) { u8* new_cached_entry = realloc(cached_entry, vfile->size); if (!new_cached_entry) { vfile->size = tick_info[vfile->offset].size; return 1; } - + cached_entry = new_cached_entry; - + if (RemoveTicketFromDB(PART_PATH, title_ids + vfile->offset * 8) != 0) { vfile->size = tick_info[vfile->offset].size; return 1; } } - + memcpy(cached_entry + offset, buffer, count); - - if ((is_tickdb ? AddTicketToDB(PART_PATH, title_ids + vfile->offset * 8, (Ticket*)(void*)cached_entry, true) : + + if ((is_tickdb ? AddTicketToDB(PART_PATH, title_ids + vfile->offset * 8, (Ticket*)(void*)cached_entry, true) : AddTitleInfoEntryToDB(PART_PATH, title_ids + vfile->offset * 8, (TitleInfoEntry*)(void*)cached_entry, true)) != 0) { if (resize) vfile->size = tick_info[vfile->offset].size; if (is_tickdb) { @@ -309,13 +309,13 @@ int WriteVBDRIFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 count cache_index = -1; return 1; } - + if (resize) tick_info[vfile->offset].size = vfile->size; - + if (tick_info && ((offset <= 0x1F1 && offset + count > 0x1F1) || (cached_entry[0x1F1] == 0 && offset <= 0x104 && offset + count > 4))) - tick_info[vfile->offset].type = (cached_entry[0x1F1] > 1) ? 3 : + tick_info[vfile->offset].type = (cached_entry[0x1F1] > 1) ? 3 : ((ValidateTicketSignature((Ticket*)(void*)cached_entry) != 0) ? 1 : ((cached_entry[0x1F1] == 1) ? 2 : 0)); - + return 0; } @@ -333,7 +333,7 @@ int DeleteVBDRIFile(const VirtualFile* vfile) { memset(title_ids + vfile->offset * 8, 0, 8); } - + return ret; } diff --git a/arm9/source/virtual/vcart.c b/arm9/source/virtual/vcart.c index 607b6ad..74e9610 100644 --- a/arm9/source/virtual/vcart.c +++ b/arm9/source/virtual/vcart.c @@ -25,14 +25,14 @@ bool ReadVCartDir(VirtualFile* vfile, VirtualDir* vdir) { if ((vdir->index < 0) && !cart_init) InitVCartDrive(); if (!cart_init) return false; - + const char* ext = (cdata->cart_type & CART_CTR) ? "3ds" : "nds"; char name[24]; GetCartName(name, cdata); memset(vfile, 0, sizeof(VirtualFile)); vfile->keyslot = 0xFF; // unused vfile->flags = VFLAG_READONLY; - + while (++vdir->index <= 7) { if ((vdir->index == 0) && (cdata->data_size < FAT_LIMIT)) { // standard full rom snprintf(vfile->name, 32, "%s.%s", name, ext); @@ -69,7 +69,7 @@ bool ReadVCartDir(VirtualFile* vfile, VirtualDir* vdir) { return true; } } - + return false; } diff --git a/arm9/source/virtual/vdisadiff.c b/arm9/source/virtual/vdisadiff.c index c218fee..a4ced47 100644 --- a/arm9/source/virtual/vdisadiff.c +++ b/arm9/source/virtual/vdisadiff.c @@ -31,39 +31,39 @@ static void AlignDisaDiffIvfcRange(DisaDiffIvfcRange* range, u32 log_block_size) static u32 MergeDisaDiffIvfcRange(DisaDiffIvfcRange new_range, DisaDiffIvfcRange* ranges, u32* n_ranges) { const u32 new_end_offset = new_range.offset + new_range.size; bool add_range = true; - + if (*n_ranges > MAX_IVFC_RANGES) return 1; - + for (u32 i = 0; i < *n_ranges; i++) { u32 end_offset = ranges[i].offset + ranges[i].size; - + if (new_range.offset > ranges[i].offset) { if (end_offset >= new_range.offset) { add_range = false; - + if (end_offset < new_end_offset) { ranges[i].size += new_end_offset - end_offset; } - + break; } - + continue; } else if (ranges[i].offset > new_range.offset) { if (new_end_offset >= ranges[i].offset) { add_range = false; - + if (new_end_offset < end_offset) { ranges[i].offset = new_range.offset; ranges[i].size = new_range.size + end_offset - new_end_offset; } else { ranges[i] = new_range; } - + break; } - + continue; } else { add_range = false; @@ -71,46 +71,46 @@ static u32 MergeDisaDiffIvfcRange(DisaDiffIvfcRange new_range, DisaDiffIvfcRange break; } } - + if (add_range) { if (*n_ranges == MAX_IVFC_RANGES - 1) return 1; - + ranges[(*n_ranges)++] = new_range; } - + return 0; } static u32 FixVDisaDiffIvfcHashChain(bool partitionB) { VDisaDiffPartitionInfo* info = partitionB ? partitionB_info : partitionA_info; if (!info) return 1; - + if (info->n_ivfc_ranges == 0) return 0; - + DisaDiffIvfcRange* ivfc_range_buffer = malloc(sizeof(DisaDiffIvfcRange) * MAX_IVFC_RANGES); if (!ivfc_range_buffer) return 1; - + u32 n_ivfc_ranges = 0; - + for (u32 i = 0; i < info->n_ivfc_ranges; i++) { if (MergeDisaDiffIvfcRange(info->ivfc_lvl4_ranges[i], ivfc_range_buffer, &n_ivfc_ranges) != 0) return 1; } - + for (u32 level = 4; level > 0; level--) { u32 next_n_ivfc_ranges = 0; DisaDiffIvfcRange* ivfc_ranges = (level % 2) ? info->ivfc_lvl4_ranges : ivfc_range_buffer; DisaDiffIvfcRange* next_ivfc_ranges = (level % 2) ? ivfc_range_buffer : info->ivfc_lvl4_ranges; - + for (u32 j = 0; j < n_ivfc_ranges; j++) { DisaDiffIvfcRange next_range; - + if (FixDisaDiffIvfcLevel(&(info->rw_info), level, ivfc_ranges[j].offset, ivfc_ranges[j].size, &(next_range.offset), &(next_range.size)) != 0) return 1; - + if (next_ivfc_ranges) { AlignDisaDiffIvfcRange(&next_range, (&(info->rw_info.log_ivfc_lvl1))[level - 2]); if (MergeDisaDiffIvfcRange(next_range, next_ivfc_ranges, &next_n_ivfc_ranges) != 0) @@ -119,12 +119,12 @@ static u32 FixVDisaDiffIvfcHashChain(bool partitionB) { } n_ivfc_ranges = next_n_ivfc_ranges; } - + free(ivfc_range_buffer); - + if (FixDisaDiffIvfcLevel(&(info->rw_info), 0, 0, 0, NULL, NULL) != 0) return 1; - + info->n_ivfc_ranges = 0; return 0; } @@ -137,7 +137,7 @@ void DeinitVDisaDiffDrive(void) { free(partitionA_info); partitionA_info = NULL; } - + if (partitionB_info) { FixVDisaDiffIvfcHashChain(true); if (partitionB_info->rw_info.dpfs_lvl2_cache) @@ -150,28 +150,28 @@ void DeinitVDisaDiffDrive(void) { u64 InitVDisaDiffDrive(void) { DisaDiffRWInfo info; u64 type; - + DeinitVDisaDiffDrive(); - + if (!(type = (GetMountState() & (SYS_DISA | SYS_DIFF)))) return 0; - + if ((GetDisaDiffRWInfo(NULL, &info, false) != 0) || (!(info.dpfs_lvl2_cache = (u8*) malloc(info.size_dpfs_lvl2)) || (BuildDisaDiffDpfsLvl2Cache(NULL, &info, info.dpfs_lvl2_cache, info.size_dpfs_lvl2) != 0))) { free(info.dpfs_lvl2_cache); return 0; } - + if (!(partitionA_info = malloc(sizeof(VDisaDiffPartitionInfo)))) { free(info.dpfs_lvl2_cache); partitionA_info = NULL; return 0; } - + memset(partitionA_info, 0, sizeof(VDisaDiffPartitionInfo)); partitionA_info->rw_info = info; - + if ((type & SYS_DISA) && (GetDisaDiffRWInfo(NULL, &info, true) == 0)) { if (!(info.dpfs_lvl2_cache = (u8*) malloc(info.size_dpfs_lvl2)) || (BuildDisaDiffDpfsLvl2Cache(NULL, &info, info.dpfs_lvl2_cache, info.size_dpfs_lvl2) != 0)) { @@ -180,7 +180,7 @@ u64 InitVDisaDiffDrive(void) { partitionA_info = NULL; return 0; } - + if (!(partitionB_info = malloc(sizeof(VDisaDiffPartitionInfo)))) { if (info.dpfs_lvl2_cache) free(info.dpfs_lvl2_cache); if (partitionA_info->rw_info.dpfs_lvl2_cache) free(partitionA_info->rw_info.dpfs_lvl2_cache); @@ -189,19 +189,19 @@ u64 InitVDisaDiffDrive(void) { partitionB_info = NULL; return 0; } - + memset(partitionB_info, 0, sizeof(VDisaDiffPartitionInfo)); partitionB_info->rw_info = info; } - + InitVBDRIDrive(); - + return type; } u64 CheckVDisaDiffDrive(void) { u64 type = GetMountState(); - + return ((type & (SYS_DISA | SYS_DIFF)) && partitionA_info) ? type : 0; } @@ -209,17 +209,17 @@ u64 CheckVDisaDiffDrive(void) { bool ReadVDisaDiffDir(VirtualFile* vfile, VirtualDir* vdir) { if (++(vdir->index) > 1) return false; - + VDisaDiffPartitionInfo* info = vdir->index ? partitionB_info : partitionA_info; - + if (!info) return false; - + memset(vfile, 0, sizeof(VirtualFile)); snprintf(vfile->name, 32, "partition%c.bin", vdir->index ? 'B' : 'A'); vfile->size = info->rw_info.size_ivfc_lvl4; if (vdir->index) vfile->flags |= VFLAG_PARTITION_B; - + return true; } @@ -234,9 +234,9 @@ int ReadVDisaDiffFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 co int WriteVDisaDiffFile(const VirtualFile* vfile, const void* buffer, u64 offset, u64 count) { VDisaDiffPartitionInfo* info = (vfile->flags & VFLAG_PARTITION_B) ? partitionB_info : partitionA_info; if (!info) return 1; - + if (WriteDisaDiffIvfcLvl4(NULL, &(info->rw_info), offset, count, buffer) != count) return 1; - + DisaDiffIvfcRange range; range.offset = offset; range.size = count; @@ -245,6 +245,6 @@ int WriteVDisaDiffFile(const VirtualFile* vfile, const void* buffer, u64 offset, ((FixVDisaDiffIvfcHashChain(vfile->flags & VFLAG_PARTITION_B) != 0) || (MergeDisaDiffIvfcRange(range, info->ivfc_lvl4_ranges, &(info->n_ivfc_ranges)) != 0))) return 1; - + return 0; } diff --git a/arm9/source/virtual/vgame.c b/arm9/source/virtual/vgame.c index 798e99e..d04aa16 100644 --- a/arm9/source/virtual/vgame.c +++ b/arm9/source/virtual/vgame.c @@ -126,7 +126,7 @@ int ReadCbcImageBlocks(void* buffer, u64 block, u64 count, u8* iv0, u64 block0) if (block == block0) memcpy(ctr, iv0, AES_BLOCK_SIZE); else if ((ret = ReadImageBytes(ctr, (block-1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE)) != 0) return ret; - + u32 mode = AES_CNT_TITLEKEY_DECRYPT_MODE; cbc_decrypt(buffer, buffer, count, mode, ctr); } @@ -139,7 +139,7 @@ int ReadCbcImageBytes(void* buffer, u64 offset, u64 count, u8* iv0, u64 offset0) u8 __attribute__((aligned(32))) temp[AES_BLOCK_SIZE]; u8* buffer8 = (u8*) buffer; int ret = 0; - + if (off_fix) { // misaligned offset (at beginning) u32 fix_byte = ((off_fix + count) >= AES_BLOCK_SIZE) ? AES_BLOCK_SIZE - off_fix : count; if ((ret = ReadCbcImageBlocks(temp, offset / AES_BLOCK_SIZE, 1, iv0, block0)) != 0) @@ -149,7 +149,7 @@ int ReadCbcImageBytes(void* buffer, u64 offset, u64 count, u8* iv0, u64 offset0) offset += fix_byte; count -= fix_byte; } - + if (count >= AES_BLOCK_SIZE) { u64 blocks = count / AES_BLOCK_SIZE; if ((ret = ReadCbcImageBlocks(buffer8, offset / AES_BLOCK_SIZE, blocks, iv0, block0)) != 0) @@ -158,14 +158,14 @@ int ReadCbcImageBytes(void* buffer, u64 offset, u64 count, u8* iv0, u64 offset0) offset += AES_BLOCK_SIZE * blocks; count -= AES_BLOCK_SIZE * blocks; } - + if (count) { // misaligned offset (at end) if ((ret = ReadCbcImageBlocks(temp, offset / AES_BLOCK_SIZE, 1, iv0, block0)) != 0) return ret; memcpy(buffer8, temp, count); count = 0; } - + return ret; } @@ -175,12 +175,12 @@ int ReadCiaContentImageBytes(void* buffer, u64 offset, u64 count, u32 cia_cnt_id memcpy(tik, cia_titlekey, 16); setup_aeskey(0x11, tik); use_aeskey(0x11); - + // setup IV0 u8 iv0[AES_BLOCK_SIZE] = { 0 }; iv0[0] = (cia_cnt_idx >> 8) & 0xFF; iv0[1] = (cia_cnt_idx >> 0) & 0xFF; - + // continue in next function u8* iv0_ptr = (cia_cnt_idx <= 0xFFFF) ? iv0 : NULL; return ReadCbcImageBytes(buffer, offset, count, iv0_ptr, offset0); @@ -205,7 +205,7 @@ int ReadNcchImageBytes(void* buffer, u64 offset, u64 count) { bool BuildVGameExeFsDir(void) { VirtualFile* templates = templates_exefs; u32 n = 0; - + for (u32 i = 0; i < 10; i++) { ExeFsFileHeader* file = exefs->files + i; if (file->size == 0) continue; @@ -217,7 +217,7 @@ bool BuildVGameExeFsDir(void) { templates[n].flags = VFLAG_EXEFS_FILE; n++; } - + n_templates_exefs = n; return true; } @@ -225,10 +225,10 @@ bool BuildVGameExeFsDir(void) { bool BuildVGameNcchDir(void) { VirtualFile* templates = templates_ncch; u32 n = 0; - + // NCCH crypto bool ncch_crypto = (NCCH_ENCRYPTED(ncch)) && (SetupNcchCrypto(ncch, NCCH_NOCRYPTO) == 0); - + // header strncpy(templates[n].name, NAME_NCCH_HEADER, 32); templates[n].offset = offset_ncch + 0; @@ -236,7 +236,7 @@ bool BuildVGameNcchDir(void) { templates[n].keyslot = 0xFF; templates[n].flags = VFLAG_NCCH; n++; - + // extended header if (ncch->size_exthdr) { strncpy(templates[n].name, NAME_NCCH_EXTHEADER, 32); @@ -246,7 +246,7 @@ bool BuildVGameNcchDir(void) { templates[n].flags = VFLAG_EXTHDR; n++; } - + // plain region if (ncch->size_plain) { strncpy(templates[n].name, NAME_NCCH_PLAIN, 32); @@ -256,7 +256,7 @@ bool BuildVGameNcchDir(void) { templates[n].flags = VFLAG_NCCH; n++; } - + // logo region if (ncch->size_logo) { strncpy(templates[n].name, NAME_NCCH_LOGO, 32); @@ -266,7 +266,7 @@ bool BuildVGameNcchDir(void) { templates[n].flags = VFLAG_NCCH; n++; } - + // exefs if (ncch->size_exefs) { strncpy(templates[n].name, NAME_NCCH_EXEFS, 32); @@ -282,7 +282,7 @@ bool BuildVGameNcchDir(void) { n++; } } - + // romfs if (ncch->size_romfs) { strncpy(templates[n].name, NAME_NCCH_ROMFS, 32); @@ -298,16 +298,16 @@ bool BuildVGameNcchDir(void) { n++; } } - + n_templates_ncch = n; return true; } - + bool BuildVGameNcsdDir(void) { const char* name_type[] = { NAME_NCSD_TYPES }; VirtualFile* templates = templates_ncsd; u32 n = 0; - + // header strncpy(templates[n].name, NAME_NCSD_HEADER, 32); templates[n].offset = 0; @@ -315,7 +315,7 @@ bool BuildVGameNcsdDir(void) { templates[n].keyslot = 0xFF; templates[n].flags = 0; n++; - + // card info header if (ncsd->partitions[0].offset * NCSD_MEDIA_UNIT >= NCSD_CINFO_OFFSET + NCSD_CINFO_SIZE) { strncpy(templates[n].name, NAME_NCSD_CARDINFO, 32); @@ -325,7 +325,7 @@ bool BuildVGameNcsdDir(void) { templates[n].flags = 0; n++; } - + // dev info header if (ncsd->partitions[0].offset * NCSD_MEDIA_UNIT >= NCSD_DINFO_OFFSET + NCSD_DINFO_SIZE) { strncpy(templates[n].name, NAME_NCSD_DEVINFO, 32); @@ -335,7 +335,7 @@ bool BuildVGameNcsdDir(void) { templates[n].flags = 0; n++; } - + // contents for (u32 i = 0; i < 8; i++) { NcchPartition* partition = ncsd->partitions + i; @@ -352,7 +352,7 @@ bool BuildVGameNcsdDir(void) { templates[n].flags |= (VFLAG_NCCH | VFLAG_DIR); n++; } - + n_templates_ncsd = n; return true; } @@ -361,10 +361,10 @@ bool BuildVGameCiaDir(void) { CiaInfo info; VirtualFile* templates = templates_cia; u32 n = 0; - + if (GetCiaInfo(&info, &(cia->header)) != 0) return false; - + // header strncpy(templates[n].name, NAME_CIA_HEADER, 32); templates[n].offset = 0; @@ -372,7 +372,7 @@ bool BuildVGameCiaDir(void) { templates[n].keyslot = 0xFF; templates[n].flags = VFLAG_NO_CRYPTO; n++; - + // certificates if (info.size_cert) { strncpy(templates[n].name, NAME_CIA_CERT, 32); @@ -382,7 +382,7 @@ bool BuildVGameCiaDir(void) { templates[n].flags = VFLAG_NO_CRYPTO; n++; } - + // ticket if (info.size_ticket) { strncpy(templates[n].name, NAME_CIA_TICKET, 32); @@ -392,7 +392,7 @@ bool BuildVGameCiaDir(void) { templates[n].flags = VFLAG_NO_CRYPTO; n++; } - + // TMD (the full thing) if (info.size_tmd) { strncpy(templates[n].name, NAME_CIA_TMD, 32); @@ -402,7 +402,7 @@ bool BuildVGameCiaDir(void) { templates[n].flags = VFLAG_NO_CRYPTO; n++; } - + // TMD content chunks if (info.size_content_list) { strncpy(templates[n].name, NAME_CIA_TMDCHUNK, 32); @@ -412,7 +412,7 @@ bool BuildVGameCiaDir(void) { templates[n].flags = VFLAG_NO_CRYPTO; n++; } - + // meta if (info.size_meta) { strncpy(templates[n].name, NAME_CIA_META, 32); @@ -428,7 +428,7 @@ bool BuildVGameCiaDir(void) { templates[n].flags = VFLAG_NO_CRYPTO; n++; } - + // contents if (info.size_content) { TmdContentChunk* content_list = cia->content_list; @@ -443,7 +443,7 @@ bool BuildVGameCiaDir(void) { if (!(cnt_index[index/8] & (1 << (7-(index%8))))) continue; // skip missing contents - + u32 cnt_type = 0; if (size >= 0x200) { u8 header[0x200]; @@ -451,25 +451,25 @@ bool BuildVGameCiaDir(void) { cnt_type = (ValidateNcchHeader((NcchHeader*)(void*)header) == 0) ? VFLAG_NCCH : (ValidateTwlHeader((TwlHeader*)(void*)header) == 0) ? VFLAG_NDS : 0; } - + snprintf(templates[n].name, 32, NAME_CIA_CONTENT, index, id, ".app"); templates[n].offset = next_offset; templates[n].size = size; templates[n].keyslot = keyslot; // keyslot is used for CIA content index here templates[n].flags = VFLAG_CIA_CONTENT; n++; - + if (cnt_type) { memcpy(templates + n, templates + n - 1, sizeof(VirtualFile)); snprintf(templates[n].name, 32, NAME_CIA_CONTENT, index, id, ""); templates[n].flags |= (cnt_type | VFLAG_DIR); n++; } - + next_offset += size; } } - + n_templates_cia = n; return true; } @@ -477,7 +477,7 @@ bool BuildVGameCiaDir(void) { bool BuildVGameNdsDir(void) { VirtualFile* templates = templates_nds; u32 n = 0; - + // header strncpy(templates[n].name, NAME_NDS_HEADER, 32); templates[n].offset = offset_nds + 0; @@ -485,7 +485,7 @@ bool BuildVGameNdsDir(void) { templates[n].keyslot = 0xFF; templates[n].flags = 0; n++; - + // banner if (twl->icon_offset) { u16 v = 0; @@ -497,7 +497,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = 0; n++; } - + // ARM9 section (+ ARM9 section footer) if (twl->arm9_size) { u32 f = 0; @@ -510,7 +510,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = 0; n++; } - + // ARM9 overlay section if (twl->arm9_overlay_size) { strncpy(templates[n].name, NAME_NDS_ARM9OVL, 32); @@ -520,7 +520,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = 0; n++; } - + // ARM9i section if ((twl->unit_code != TWL_UNITCODE_NTR) && (twl->arm9i_size)) { strncpy(templates[n].name, NAME_NDS_ARM9I, 32); @@ -530,7 +530,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = 0; n++; } - + // ARM7 section if (twl->arm7_size) { strncpy(templates[n].name, NAME_NDS_ARM7, 32); @@ -540,7 +540,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = 0; n++; } - + // ARM7 overlay section if (twl->arm7_overlay_size) { strncpy(templates[n].name, NAME_NDS_ARM7OVL, 32); @@ -550,7 +550,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = 0; n++; } - + // ARM7i section if ((twl->unit_code != TWL_UNITCODE_NTR) && (twl->arm7i_size)) { strncpy(templates[n].name, NAME_NDS_ARM7I, 32); @@ -560,7 +560,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = 0; n++; } - + // data if (twl->fnt_size && twl->fat_size && (twl->fnt_offset < twl->fat_offset)) { strncpy(templates[n].name, NAME_NDS_DATADIR, 32); @@ -570,7 +570,7 @@ bool BuildVGameNdsDir(void) { templates[n].flags = VFLAG_NITRO_DIR | VFLAG_DIR; n++; } - + n_templates_nds = n; return true; } @@ -578,7 +578,7 @@ bool BuildVGameNdsDir(void) { bool BuildVGameFirmDir(void) { VirtualFile* templates = templates_firm; u32 n = 0; - + // header strncpy(templates[n].name, NAME_FIRM_HEADER, 32); templates[n].offset = 0; @@ -586,7 +586,7 @@ bool BuildVGameFirmDir(void) { templates[n].keyslot = 0xFF; templates[n].flags = 0; n++; - + // arm9 binary (only for encrypted) if (offset_a9bin != (u64) -1) { strncpy(templates[n].name, NAME_FIRM_ARM9BIN, 32); @@ -596,7 +596,7 @@ bool BuildVGameFirmDir(void) { templates[n].flags = 0; n++; } - + // section binaries & NCCHs for (u32 i = 0; i < 4; i++) { FirmSectionHeader* section = firm->sections + i; @@ -614,7 +614,7 @@ bool BuildVGameFirmDir(void) { NcchHeader p9_ncch; char name[8]; u32 offset_p9 = 0; - + u8* buffer = (u8*) malloc(section->size); if (buffer) { if (ReadGameImageBytes(buffer, section->offset, section->size) != 0) break; @@ -627,7 +627,7 @@ bool BuildVGameFirmDir(void) { } free(buffer); } - + if (offset_p9) { snprintf(templates[n].name, 32, NAME_FIRM_NCCH, p9_ncch.programId, name, ".app"); templates[n].offset = offset_p9; @@ -651,7 +651,7 @@ bool BuildVGameFirmDir(void) { (ReadImageBytes((u8*) name, section->offset + p + 0x200, 0x8) != 0) || (ValidateNcchHeader(&firm_ncch) != 0)) break; - + snprintf(templates[n].name, 32, NAME_FIRM_NCCH, firm_ncch.programId, name, ".app"); templates[n].offset = section->offset + p; templates[n].size = firm_ncch.size * NCCH_MEDIA_UNIT; @@ -666,7 +666,7 @@ bool BuildVGameFirmDir(void) { } } } - + n_templates_firm = n; return true; } @@ -676,7 +676,7 @@ bool BuildVGameTadDir(void) { VirtualFile* templates = templates_tad; u32 content_offset = 0; u32 n = 0; - + // read header, setup table u8 ALIGN(32) hdr_data[TAD_HEADER_LEN]; TadHeader* hdr = (void*)hdr_data; @@ -686,7 +686,7 @@ bool BuildVGameTadDir(void) { n_templates_tad = 0; return false; } - + // banner strncpy(templates[n].name, NAME_TAD_BANNER, 32); templates[n].offset = content_offset; @@ -695,7 +695,7 @@ bool BuildVGameTadDir(void) { templates[n].flags = 0; content_offset = tbl.banner_end; n++; - + // header strncpy(templates[n].name, NAME_TAD_HEADER, 32); templates[n].offset = content_offset; @@ -704,7 +704,7 @@ bool BuildVGameTadDir(void) { templates[n].flags = 0; content_offset = tbl.header_end; n++; - + // footer strncpy(templates[n].name, NAME_TAD_FOOTER, 32); templates[n].offset = content_offset; @@ -713,7 +713,7 @@ bool BuildVGameTadDir(void) { templates[n].flags = 0; content_offset = tbl.footer_end; n++; - + // contents for (u32 i = 0; i < TAD_NUM_CONTENT; content_offset = tbl.content_end[i++]) { if (!hdr->content_size[i]) continue; // nothing in section @@ -731,7 +731,7 @@ bool BuildVGameTadDir(void) { n++; } } - + n_templates_tad = n; return true; } @@ -745,10 +745,10 @@ void DeinitVGameDrive(void) { u64 InitVGameDrive(void) { // prerequisite: game file mounted as image u64 type = GetMountState(); - + vgame_type = 0; DeinitVGameDrive(); - + offset_firm = (u64) -1; offset_a9bin = (u64) -1; offset_cia = (u64) -1; @@ -761,7 +761,7 @@ u64 InitVGameDrive(void) { // prerequisite: game file mounted as image offset_nds = (u64) -1; offset_nitro = (u64) -1; offset_tad = (u64) -1; - + base_vdir = (type & SYS_FIRM ) ? VFLAG_FIRM : (type & GAME_CIA ) ? VFLAG_CIA : @@ -792,7 +792,7 @@ u64 InitVGameDrive(void) { // prerequisite: game file mounted as image ncch = (NcchHeader*) (void*) (((u8*) vgame_buffer) + 0x3FC00); // 512 byte reserved exefs = (ExeFsHeader*) (void*) (((u8*) vgame_buffer) + 0x3FE00); // 512 byte reserved // filesystem stuff (RomFS / NitroFS) will be allocated on demand - + vgame_type = type; return type; } @@ -816,7 +816,7 @@ bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry) { vdir->size = ventry->size; vdir->flags = ventry->flags; } - + // CIA content special handling if (vdir->flags & VFLAG_CIA) { // disable content crypto offset_ccnt = (u64) -1; @@ -825,7 +825,7 @@ bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry) { offset_ccnt = vdir->offset; index_ccnt = ventry->keyslot; } - + // build directories where required if ((vdir->flags & VFLAG_FIRM) && (offset_firm != vdir->offset)) { if ((ReadImageBytes((u8*) firm, 0, sizeof(FirmHeader)) != 0) || @@ -921,8 +921,8 @@ bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry) { return false; offset_nitro = offset_nds; } - - // for romfs/nitro dir: switch to lv3/nitro object + + // for romfs/nitro dir: switch to lv3/nitro object if (vdir->flags & (VFLAG_ROMFS|VFLAG_NITRO_DIR)) { vdir->index = -1; vdir->offset = 0; @@ -931,19 +931,19 @@ bool OpenVGameDir(VirtualDir* vdir, VirtualFile* ventry) { if (vdir->flags & VFLAG_NITRO_DIR) vdir->flags |= VFLAG_NITRO; vdir->flags &= ~(VFLAG_ROMFS|VFLAG_NITRO_DIR); } - + return true; } bool ReadVGameDirLv3(VirtualFile* vfile, VirtualDir* vdir) { vfile->name[0] = '\0'; vfile->flags = VFLAG_LV3 | VFLAG_READONLY; - vfile->keyslot = ((offset_ncch != (u64) -1) && NCCH_ENCRYPTED(ncch)) ? + vfile->keyslot = ((offset_ncch != (u64) -1) && NCCH_ENCRYPTED(ncch)) ? 0x2C : 0xFF; // actual keyslot may be different - + // start from parent dir object - if (vdir->index == -1) vdir->index = 0; - + if (vdir->index == -1) vdir->index = 0; + // first child file object, skip if not available if (vdir->index == 0) { RomFsLv3DirMeta* parent = LV3_GET_DIR(vdir->offset, &lv3idx); @@ -958,7 +958,7 @@ bool ReadVGameDirLv3(VirtualFile* vfile, VirtualDir* vdir) { return true; } else vdir->index = 2; } - + // parse sibling files if (vdir->index == 1) { RomFsLv3FileMeta* current = LV3_GET_FILE(vdir->offset, &lv3idx); @@ -975,7 +975,7 @@ bool ReadVGameDirLv3(VirtualFile* vfile, VirtualDir* vdir) { vdir->index = 2; } else return false; } - + // first child dir object, skip if not available if (vdir->index == 2) { RomFsLv3DirMeta* parent = LV3_GET_DIR(vdir->offset, &lv3idx); @@ -988,7 +988,7 @@ bool ReadVGameDirLv3(VirtualFile* vfile, VirtualDir* vdir) { return true; } else vdir->index = 4; } - + // parse sibling dirs if (vdir->index == 3) { RomFsLv3DirMeta* current = LV3_GET_DIR(vdir->offset, &lv3idx); @@ -1003,18 +1003,18 @@ bool ReadVGameDirLv3(VirtualFile* vfile, VirtualDir* vdir) { vdir->index = 4; } else return false; } - + return false; } bool ReadVGameDirNitro(VirtualFile* vfile, VirtualDir* vdir) { u8* fnt = vgame_fs_buffer; u8* fat = vgame_fs_buffer + twl->fat_offset - twl->fnt_offset; - + vfile->name[0] = '\0'; vfile->flags = VFLAG_NITRO | VFLAG_READONLY; vfile->keyslot = 0; - + // start from parent dir object if (vdir->index == -1) { u8* fnt_entry = NULL; @@ -1025,7 +1025,7 @@ bool ReadVGameDirNitro(VirtualFile* vfile, VirtualDir* vdir) { vdir->offset = (vdir->offset&0xFFFFFFFF) | (((u64)(fnt_entry - fnt)) << 32); // store offsets in offset } else vdir->index = -3; // error } - + // read directory entries until done if (vdir->index >= 0) { u8* fnt_entry = fnt + (vdir->offset >> 32); @@ -1041,14 +1041,14 @@ bool ReadVGameDirNitro(VirtualFile* vfile, VirtualDir* vdir) { vdir->offset = (vdir->offset&0xFFFFFFFF) | (((u64)(fnt_entry - fnt)) << 32); } else vdir->index = -2; // end of dir } - + return (vdir->index >= 0); } - + bool ReadVGameDir(VirtualFile* vfile, VirtualDir* vdir) { VirtualFile* templates = NULL; int n = 0; - + if (vdir->flags & VFLAG_FIRM) { templates = templates_firm; n = n_templates_firm; @@ -1075,14 +1075,14 @@ bool ReadVGameDir(VirtualFile* vfile, VirtualDir* vdir) { } else if (vdir->flags & VFLAG_NITRO) { return ReadVGameDirNitro(vfile, vdir); } - + if (++vdir->index < n) { // copy current template to vfile and set readonly flag memcpy(vfile, templates + vdir->index, sizeof(VirtualFile)); vfile->flags |= VFLAG_READONLY; return true; } - + return false; } @@ -1110,7 +1110,7 @@ bool FindVirtualFileInLv3Dir(VirtualFile* vfile, const VirtualDir* vdir, const c vfile->flags = vdir->flags & ~VFLAG_DIR; vfile->keyslot = ((offset_ncch != (u64) -1) && NCCH_ENCRYPTED(ncch)) ? 0x2C : 0xFF; // actual keyslot may be different - + RomFsLv3DirMeta* lv3dir = GetLv3DirMeta(name, vdir->offset, &lv3idx); if (lv3dir) { vfile->offset = ((u8*) lv3dir) - ((u8*) lv3idx.dirmeta); @@ -1118,24 +1118,24 @@ bool FindVirtualFileInLv3Dir(VirtualFile* vfile, const VirtualDir* vdir, const c vfile->flags |= VFLAG_DIR; return true; } - + RomFsLv3FileMeta* lv3file = GetLv3FileMeta(name, vdir->offset, &lv3idx); if (lv3file) { vfile->offset = ((u8*) lv3file) - ((u8*) lv3idx.filemeta); vfile->size = lv3file->size_data; return true; } - + return false; } bool GetVGameLv3Filename(char* name, const VirtualFile* vfile, u32 n_chars) { if (!(vfile->flags & VFLAG_LV3)) return false; - + u16* wname = NULL; u32 name_len = 0; - + if (vfile->flags & VFLAG_DIR) { RomFsLv3DirMeta* dirmeta = LV3_GET_DIR(vfile->offset, &lv3idx); if (!dirmeta) return false; @@ -1149,14 +1149,14 @@ bool GetVGameLv3Filename(char* name, const VirtualFile* vfile, u32 n_chars) { } memset(name, 0, n_chars); utf16_to_utf8((u8*) name, wname, n_chars-1, name_len); - + return true; } bool GetVGameNitroFilename(char* name, const VirtualFile* vfile, u32 n_chars) { if (!(vfile->flags & VFLAG_NITRO)) return false; - + u8* fnt_entry = vgame_fs_buffer + (vfile->offset >> 32); u32 name_len = (*fnt_entry) & ~0x80; if (name_len >= n_chars) return false; @@ -1164,7 +1164,7 @@ bool GetVGameNitroFilename(char* name, const VirtualFile* vfile, u32 n_chars) { memcpy(name, fnt_entry + 1, name_len); for (u32 i = 0; i < name_len; i++) if (name[i] == '%') name[i] = '_'; - + // Shift-JIS workaround for (u32 i = 0; i < name_len; i++) { if (name[i] >= 0x80) { // this is a Shift-JIS filename @@ -1173,7 +1173,7 @@ bool GetVGameNitroFilename(char* name, const VirtualFile* vfile, u32 n_chars) { break; } } - + return true; } diff --git a/arm9/source/virtual/virtual.c b/arm9/source/virtual/virtual.c index ecfb396..e960e03 100644 --- a/arm9/source/virtual/virtual.c +++ b/arm9/source/virtual/virtual.c @@ -112,17 +112,17 @@ bool GetVirtualFile(VirtualFile* vfile, const char* path, u8 mode) { char lpath[256]; strncpy(lpath, path, 256); lpath[255] = '\0'; - + // get virtual source / root dir object u32 virtual_src = 0; virtual_src = GetVirtualSource(path); if (!virtual_src) return false; - + // set vfile as root object memset(vfile, 0, sizeof(VirtualDir)); vfile->flags = VFLAG_ROOT|virtual_src; if (strnlen(lpath, 256) <= 3) return true; - + // tokenize / parse path char* name; VirtualDir vdir; @@ -130,7 +130,7 @@ bool GetVirtualFile(VirtualFile* vfile, const char* path, u8 mode) { for (name = strtok(lpath + 3, "/"); name && vdir.flags; name = strtok(NULL, "/")) { if (!(vdir.flags & VFLAG_LV3)) { // standard method while (true) { - if (!ReadVirtualDir(vfile, &vdir)) + if (!ReadVirtualDir(vfile, &vdir)) return ((mode & FA_WRITE) && (vdir.flags & VRT_BDRI) && GetNewVBDRIFile(vfile, &vdir, path)); if ((!(vfile->flags & (VRT_GAME|VRT_VRAM)) && (strncasecmp(name, vfile->name, 32) == 0)) || ((vfile->flags & VRT_GAME) && MatchVGameFilename(name, vfile, 256)) || @@ -144,7 +144,7 @@ bool GetVirtualFile(VirtualFile* vfile, const char* path, u8 mode) { if (!OpenVirtualDir(&vdir, vfile)) vdir.flags = 0; } - + return (name == NULL); // if name is NULL, this succeeded } @@ -156,7 +156,7 @@ bool GetVirtualDir(VirtualDir* vdir, const char* path) { bool GetVirtualFilename(char* name, const VirtualFile* vfile, u32 n_chars) { if (vfile->flags & VRT_GAME) return GetVGameFilename(name, vfile, n_chars); else if (vfile->flags & VRT_VRAM) return GetVVramFilename(name, vfile); - + strncpy(name, vfile->name, n_chars); return true; } @@ -168,7 +168,7 @@ int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 coun else if ((offset + count) > vfile->size) count = vfile->size - offset; if (bytes_read) *bytes_read = count; - + if (vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND|VRT_XORPAD)) { return ReadVNandFile(vfile, buffer, offset, count); } else if (vfile->flags & VRT_MEMORY) { @@ -186,7 +186,7 @@ int ReadVirtualFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 coun } else if (vfile->flags & VRT_DISADIFF) { return ReadVDisaDiffFile(vfile, buffer, offset, count); } - + return -1; } @@ -197,7 +197,7 @@ int WriteVirtualFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 cou else if (!(vfile->flags & VRT_BDRI) && ((offset + count) > vfile->size)) count = vfile->size - offset; if (bytes_written) *bytes_written = count; - + if (vfile->flags & VFLAG_READONLY) { return -1; } else if (vfile->flags & (VRT_SYSNAND|VRT_EMUNAND|VRT_IMGNAND)) { @@ -211,30 +211,30 @@ int WriteVirtualFile(VirtualFile* vfile, const void* buffer, u64 offset, u64 cou } else if (vfile->flags & VRT_BDRI) { return WriteVBDRIFile(vfile, buffer, offset, count); } // no write support for virtual game / keydb / vram files - + return -1; } int DeleteVirtualFile(const VirtualFile* vfile) { if (!(vfile->flags & VFLAG_DELETABLE)) return -1; - + // Special handling for deleting BDRI entries if (vfile->flags & VRT_BDRI) return DeleteVBDRIFile(vfile); - + // For anything else, "deleting" is just filling with 0s u32 zeroes_size = STD_BUFFER_SIZE; u8* zeroes = (u8*) malloc(zeroes_size); if (!zeroes) return -1; memset(zeroes, 0x00, zeroes_size); - + int result = 0; for (u64 pos = 0; pos < vfile->size; pos += zeroes_size) { u64 wipe_bytes = min(zeroes_size, vfile->size - pos); result = WriteVirtualFile((VirtualFile*)vfile, zeroes, pos, wipe_bytes, NULL); if (result != 0) break; } - + free(zeroes); return result; } diff --git a/arm9/source/virtual/vkeydb.c b/arm9/source/virtual/vkeydb.c index 87c4167..1ae7f0a 100644 --- a/arm9/source/virtual/vkeydb.c +++ b/arm9/source/virtual/vkeydb.c @@ -17,28 +17,28 @@ void DeinitVKeyDbDrive(void) { u64 InitVKeyDbDrive(void) { // prerequisite: aeskeydb.bin mounted as image if (!(GetMountState() & BIN_KEYDB)) return 0; n_keys = 0; - + // sanity check u64 fsize = GetMountSize(); if (!fsize || (fsize % sizeof(AesKeyInfo)) || (fsize > VKEYDB_BUFFER_SIZE)) { n_keys = 0; return 0; } - + // setup vkeydb buffer DeinitVKeyDbDrive(); // dangerous shit key_info = (AesKeyInfo*) malloc(VKEYDB_BUFFER_SIZE); if (!key_info) return 0; - + // load the full database into memory n_keys = fsize / sizeof(AesKeyInfo); if (ReadImageBytes((u8*) key_info, 0, fsize) != 0) n_keys = 0; - + // decrypt keys if required for (u32 i = 0; i < n_keys; i++) { if (key_info[i].isEncrypted) CryptAesKeyInfo(&(key_info[i])); } - + if (!n_keys) DeinitVKeyDbDrive(); return (n_keys) ? BIN_KEYDB : 0; } @@ -59,17 +59,17 @@ bool ReadVKeyDbDir(VirtualFile* vfile, VirtualDir* vdir) { (key_entry->keyUnitType == KEYS_RETAIL) ? ".ret" : ""; snprintf(typestr, 12 + 1, "%s%.10s", (key_entry->type == 'I') ? "IV" : (key_entry->type == 'X') ? "X" : (key_entry->type == 'Y') ? "Y" : "", key_entry->id); - + memset(vfile, 0, sizeof(VirtualFile)); snprintf(vfile->name, 32, NAME_LEGKEY, keyslot, typestr, unitext); vfile->offset = vdir->index * sizeof(AesKeyInfo); vfile->size = 16; // standard size of a key vfile->keyslot = 0xFF; vfile->flags = VFLAG_READONLY; - + return true; // found } - + return false; } diff --git a/arm9/source/virtual/vmem.c b/arm9/source/virtual/vmem.c index b257c6f..f07978e 100644 --- a/arm9/source/virtual/vmem.c +++ b/arm9/source/virtual/vmem.c @@ -88,23 +88,23 @@ static const VirtualFile vMemFileTemplates[] = { bool ReadVMemDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir object generated in virtual.c int n_templates = sizeof(vMemFileTemplates) / sizeof(VirtualFile); const VirtualFile* templates = vMemFileTemplates; - + while (++vdir->index < n_templates) { // copy current template to vfile memcpy(vfile, templates + vdir->index, sizeof(VirtualFile)); - + // process special flags if (((vfile->flags & VFLAG_N3DS_EXT) && (IS_O3DS)) || // this is not on O3DS consoles and locked by sighax ((vfile->flags & VFLAG_OTP) && !(IS_UNLOCKED)) || // OTP still locked ((vfile->flags & VFLAG_BOOT9) && !(HAS_BOOT9)) || // boot9 not found ((vfile->flags & VFLAG_BOOT11) && !(HAS_BOOT11)) || // boot11 not found ((vfile->flags & VFLAG_OTP_KEY) && !(HAS_OTP_KEY))) // OTP key not found - continue; - + continue; + // found if arriving here return true; } - + return false; } @@ -116,7 +116,7 @@ int ReadVMemOTPDecrypted(const VirtualFile* vfile, void* buffer, u64 offset, u64 alignas(32) u8 otp_iv[0x10]; alignas(32) u8 otp_key[0x10]; u8* otp_mem = (u8*) __OTP_ADDR; - + if (HAS_BOOT9) { // easy setup when boot9 available memcpy(otp_iv, OTP_IV, 0x10); memcpy(otp_key, OTP_KEY, 0x10); @@ -125,7 +125,7 @@ int ReadVMemOTPDecrypted(const VirtualFile* vfile, void* buffer, u64 offset, u64 (LoadKeyFromFile(otp_iv , 0x11, 'I', "OTP") != 0)) return 1; // crypto not available } - + setup_aeskey(0x11, otp_key); use_aeskey(0x11); cbc_decrypt(otp_mem, otp_local, __OTP_LEN / 0x10, AES_CNT_TITLEKEY_DECRYPT_MODE, otp_iv); @@ -149,7 +149,7 @@ int ReadVMemMCURegisters(const VirtualFile* vfile, void* buffer, u64 offset, u64 int ReadVMemFlashCID(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) { // NAND CID if keyslot field != 0. bool is_nand = (bool)vfile->keyslot; - + u32 cid[4]; // CID is 16 byte in size sdmmc_get_cid(is_nand, (u32*) cid); memcpy(buffer, ((u8*) cid) + offset, count); @@ -160,7 +160,7 @@ int ReadVMemFlashCID(const VirtualFile* vfile, void* buffer, u64 offset, u64 cou int ReadVMemNVRAM(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) { static bool wififlash_initialized = false; (void) vfile; - + if (!wififlash_initialized) { wififlash_initialized = spiflash_get_status(); if (!wififlash_initialized) return 1; diff --git a/arm9/source/virtual/vnand.c b/arm9/source/virtual/vnand.c index fd4827b..9dfb47f 100644 --- a/arm9/source/virtual/vnand.c +++ b/arm9/source/virtual/vnand.c @@ -54,11 +54,11 @@ bool ReadVNandDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir int n_templates = sizeof(vNandTemplates) / sizeof(VirtualNandTemplate); const VirtualNandTemplate* templates = vNandTemplates; u32 nand_src = vdir->flags & VRT_SOURCE; - + while (++vdir->index < n_templates) { const VirtualNandTemplate* template = templates + vdir->index; NandPartitionInfo prt_info; - + // set up virtual file if (template->flags & VFLAG_NAND_SIZE) { // override for "nand.bin" prt_info.sector = 0; @@ -71,7 +71,7 @@ bool ReadVNandDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir vfile->size = ((u64) prt_info.count) * 0x200; vfile->keyslot = prt_info.keyslot; vfile->flags = template->flags; - + // handle special cases if (!vfile->size) continue; if ((nand_src == VRT_XORPAD) && ((vfile->keyslot == 0x11) || (vfile->keyslot >= 0x40))) @@ -98,12 +98,12 @@ bool ReadVNandDir(VirtualFile* vfile, VirtualDir* vdir) { // uses a generic vdir if (sha_cmp(perfect_sha, keydb, KEYDB_PERFECT_SIZE, SHA256_MODE) != 0) continue; vfile->size = KEYDB_PERFECT_SIZE; } - + // found if arriving here vfile->flags |= nand_src; return true; } - + return false; } diff --git a/arm9/source/virtual/vvram.c b/arm9/source/virtual/vvram.c index e13724a..f156d48 100644 --- a/arm9/source/virtual/vvram.c +++ b/arm9/source/virtual/vvram.c @@ -5,13 +5,13 @@ bool SplitTarFName(char* tar_fname, char** dir, char** name) { u32 len = strnlen(tar_fname, 100 + 1); if (!len || (len == 101)) return false; - + // remove trailing slash if (tar_fname[len-1] == '/') tar_fname[--len] = '\0'; - + // find last slash char* slash = strrchr(tar_fname, '/'); - + // relative root dir entry if (!slash) { *name = tar_fname; @@ -21,7 +21,7 @@ bool SplitTarFName(char* tar_fname, char** dir, char** name) { *name = slash + 1; *dir = tar_fname; } - + return true; } @@ -34,8 +34,8 @@ bool ReadVVramDir(VirtualFile* vfile, VirtualDir* vdir) { vfile->name[0] = '\0'; vfile->flags = VFLAG_READONLY; vfile->keyslot = 0xFF; - - + + // get current dir name char curr_dir[100 + 1]; if (vdir->offset == (u64) -1) return false; // end of the dir? @@ -48,47 +48,47 @@ bool ReadVVramDir(VirtualFile* vfile, VirtualDir* vdir) { if (len == 101) return false; // path error if (curr_dir[len-1] == '/') curr_dir[len-1] = '\0'; } - - + + // using vdir index to signify the position limits us to 1TiB TARs void* tardata = NULL; if (vdir->index < 0) tardata = FirstVTarEntry(); else tardata = NextVTarEntry(OffsetVTarEntry(vdir->index << 9)); - + if (tardata) do { TarHeader* tar = (TarHeader*) tardata; char tar_fname[100 + 1]; char *name, *dir; - + strncpy(tar_fname, tar->fname, 100); if (!SplitTarFName(tar_fname, &dir, &name)) return false; if ((!dir && !*curr_dir) || (dir && (strncmp(dir, curr_dir, 100) == 0))) break; } while ((tardata = NextVTarEntry(tardata))); - + // match found? if (tardata) { u64 fsize; bool is_dir; void* fdata = GetVTarFileInfo(tardata, NULL, &fsize, &is_dir); - + vfile->offset = (u32) fdata - VRAM0_OFFSET; vfile->size = fsize; if (is_dir) vfile->flags |= VFLAG_DIR; - + vdir->index = (vfile->offset >> 9) - 1; } else { // not found vdir->offset = (u64) -1; return false; } - - + + return true; } int ReadVVramFile(const VirtualFile* vfile, void* buffer, u64 offset, u64 count) { if (vfile->flags & VFLAG_DIR) return -1; void* fdata = (u8*) VRAM0_OFFSET + vfile->offset; - + // range checks in virtual.c memcpy(buffer, (u8*) fdata + offset, count); return 0; @@ -99,11 +99,11 @@ bool GetVVramFilename(char* name, const VirtualFile* vfile) { TarHeader* tar = (TarHeader*) tardata; char tar_fname[100 + 1]; char *name_tmp, *dir; - + strncpy(tar_fname, tar->fname, 100); if (!SplitTarFName(tar_fname, &dir, &name_tmp)) return false; strncpy(name, name_tmp, 100); - + return true; } @@ -112,7 +112,7 @@ bool MatchVVramFilename(const char* name, const VirtualFile* vfile) { TarHeader* tar = (TarHeader*) tardata; char tar_fname[100 + 1]; char *name_tmp, *dir; - + strncpy(tar_fname, tar->fname, 100); if (!SplitTarFName(tar_fname, &dir, &name_tmp)) return false; return (strncasecmp(name, name_tmp, 100) == 0);