diff --git a/legacy/util.c b/legacy/util.c index ccd1605..6f84af0 100644 --- a/legacy/util.c +++ b/legacy/util.c @@ -173,245 +173,6 @@ void saveConfig() if (write_res != sizeof(dumpOptions)) remove(CONFIG_PATH); } -static bool isGameCardInserted() -{ - bool inserted = false; - fsDeviceOperatorIsGameCardInserted(&(gameCardInfo.fsOperatorInstance), &inserted); - return inserted; -} - -static void changeAtomicBool(volatile bool *ptr, bool value) -{ - if (!ptr) return; - - if (value) - { - __atomic_test_and_set(ptr, __ATOMIC_SEQ_CST); - } else { - __atomic_clear(ptr, __ATOMIC_SEQ_CST); - } -} - -static void *fsGameCardDetectionThreadFunc(void *arg) -{ - (void)arg; - - Result result = 0; - int idx = 0; - - Waiter gameCardEventWaiter = waiterForEvent(&(gameCardInfo.fsGameCardKernelEvent)); - Waiter exitEventWaiter = waiterForUEvent(&exitEvent); - - changeAtomicBool(&gameCardInfoLoaded, false); - - /* Retrieve initial gamecard status */ - bool curGcStatus = isGameCardInserted(); - changeAtomicBool(&(gameCardInfo.isInserted), curGcStatus); - - while(true) - { - // Wait until an event is triggered - result = waitMulti(&idx, -1, gameCardEventWaiter, exitEventWaiter); - if (R_FAILED(result)) continue; - - // Exit event triggered - if (idx == 1) break; - - // Retrieve current gamecard status - // Only proceed if we're dealing with a status change - curGcStatus = isGameCardInserted(); - changeAtomicBool(&(gameCardInfo.isInserted), curGcStatus); - if (!curGcStatus && gameCardInfoLoaded) changeAtomicBool(&gameCardInfoLoaded, false); - } - - waitMulti(&idx, 0, gameCardEventWaiter, exitEventWaiter); - - return 0; -} - -static bool createGameCardDetectionThread() -{ - int ret1 = 0, ret2 = 0; - pthread_attr_t attr; - - ret1 = pthread_attr_init(&attr); - if (ret1 != 0) - { - uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to initialize thread attributes! (%d)", __func__, ret1); - return false; - } - - ret1 = pthread_create(&gameCardDetectionThread, &attr, &fsGameCardDetectionThreadFunc, NULL); - if (ret1 != 0) uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to create thread! (%d)", __func__, ret1); - - ret2 = pthread_attr_destroy(&attr); - if (ret2 != 0) uiDrawString(STRING_X_POS, (ret1 == 0 ? 8 : STRING_Y_POS(1)), FONT_COLOR_ERROR_RGB, "%s: failed to destroy thread attributes! (%d)", __func__, ret2); - - if (ret1 != 0 || ret2 != 0) return false; - - return true; -} - -static void closeGameCardHandle() -{ - svcCloseHandle(gameCardInfo.fsGameCardHandle.value); - gameCardInfo.fsGameCardHandle.value = 0; -} - -void closeGameCardStoragePartition() -{ - if (!gameCardInfo.curIStorageIndex || gameCardInfo.curIStorageIndex >= ISTORAGE_PARTITION_INVALID) return; - - fsStorageClose(&(gameCardInfo.fsGameCardStorage)); - memset(&(gameCardInfo.fsGameCardStorage), 0, sizeof(FsStorage)); - - closeGameCardHandle(); - - gameCardInfo.curIStorageIndex = ISTORAGE_PARTITION_NONE; -} - -Result openGameCardStoragePartition(openIStoragePartition partitionIndex) -{ - // Check if the provided IStorage index is valid - if (!partitionIndex || partitionIndex >= ISTORAGE_PARTITION_INVALID) return MAKERESULT(Module_Libnx, LibnxError_IoError); - - // Safety check: check if we have already opened an IStorage instance - if (gameCardInfo.curIStorageIndex && gameCardInfo.curIStorageIndex < ISTORAGE_PARTITION_INVALID) - { - // If the opened IStorage instance is the same as the requested one, just return right away - if (gameCardInfo.curIStorageIndex == partitionIndex) return 0; - - // Otherwise, close the current IStorage instance - closeGameCardStoragePartition(); - } - - u8 i; - u32 idx = (u32)(partitionIndex - 1); - Result res1 = 0, res2 = 0, out = 0; - - // 10 tries - for(i = 0; i < 10; i++) - { - // First try to retrieve the IStorage partition handle using the current gamecard handle - res1 = fsOpenGameCardStorage(&(gameCardInfo.fsGameCardStorage), &(gameCardInfo.fsGameCardHandle), idx); - if (R_SUCCEEDED(res1)) break; - - // If the previous call failed, we may have an invalid handle, so let's close the current one and try to retrieve a new one - closeGameCardHandle(); - res2 = fsDeviceOperatorGetGameCardHandle(&(gameCardInfo.fsOperatorInstance), &(gameCardInfo.fsGameCardHandle)); - } - - if (R_SUCCEEDED(res1) && R_SUCCEEDED(res2)) - { - // Update current IStorage index - gameCardInfo.curIStorageIndex = partitionIndex; - } else { - // res2 takes precedence over res1 - out = (R_FAILED(res2) ? res2 : res1); - - // Close leftover gamecard handle - closeGameCardHandle(); - } - - // If everything worked properly, a functional gamecard handle + IStorage handle are guaranteed up to this point - return out; -} - -Result readGameCardStoragePartition(u64 off, void *buf, size_t len) -{ - if (!gameCardInfo.curIStorageIndex || gameCardInfo.curIStorageIndex >= ISTORAGE_PARTITION_INVALID || !buf || !len) return MAKERESULT(Module_Libnx, LibnxError_IoError); - - // Optimization for reads that are already aligned to MEDIA_UNIT_SIZE bytes - if (!(off % MEDIA_UNIT_SIZE) && !(len % MEDIA_UNIT_SIZE)) return fsStorageRead(&(gameCardInfo.fsGameCardStorage), off, buf, len); - - Result result; - u8 *outBuf = (u8*)buf; - - u64 block_start_offset = (off - (off % MEDIA_UNIT_SIZE)); - u64 block_end_offset = (u64)round_up(off + len, MEDIA_UNIT_SIZE); - u64 block_size = (block_end_offset - block_start_offset); - - u64 block_size_used = (block_size > GAMECARD_READ_BUFFER_SIZE ? GAMECARD_READ_BUFFER_SIZE : block_size); - u64 output_block_size = (block_size > GAMECARD_READ_BUFFER_SIZE ? (GAMECARD_READ_BUFFER_SIZE - (off - block_start_offset)) : len); - - result = fsStorageRead(&(gameCardInfo.fsGameCardStorage), block_start_offset, gcReadBuf, block_size_used); - if (R_FAILED(result)) return result; - - memcpy(outBuf, gcReadBuf + (off - block_start_offset), output_block_size); - - if (block_size > GAMECARD_READ_BUFFER_SIZE) return readGameCardStoragePartition(off + output_block_size, outBuf + output_block_size, len - output_block_size); - - return result; -} - -static Result getGameCardStoragePartitionSize(u64 *out) -{ - if (!gameCardInfo.curIStorageIndex || gameCardInfo.curIStorageIndex >= ISTORAGE_PARTITION_INVALID || !out) return MAKERESULT(Module_Libnx, LibnxError_IoError); - - return fsStorageGetSize(&(gameCardInfo.fsGameCardStorage), (s64*)out); -} - -bool mountSysEmmcPartition() -{ - Result result = 0; - FRESULT fr = FR_OK; - - result = fsOpenBisStorage(&fatFsStorage, FsBisPartitionId_System); - if (R_FAILED(result)) - { - uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to open BIS System partition! (0x%08X)", __func__, result); - return false; - } - - fatFsObj = calloc(1, sizeof(FATFS)); - if (!fatFsObj) - { - uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to allocate memory for FatFs object!", __func__); - return false; - } - - fr = f_mount(fatFsObj, BIS_MOUNT_NAME, 1); - if (fr != FR_OK) - { - uiDrawString(STRING_DEFAULT_POS, FONT_COLOR_ERROR_RGB, "%s: failed to mount BIS System partition! (%u)", __func__, fr); - return false; - } - - return true; -} - -void unmountSysEmmcPartition() -{ - if (fatFsObj) - { - f_unmount(BIS_MOUNT_NAME); - free(fatFsObj); - fatFsObj = NULL; - } - - if (serviceIsActive(&(fatFsStorage.s))) - { - fsStorageClose(&fatFsStorage); - memset(&fatFsStorage, 0, sizeof(FsStorage)); - } -} - -static bool isServiceRunning(const char *name) -{ - if (!name || !strlen(name)) return false; - - Handle handle; - SmServiceName serviceName = smEncodeName(name); - Result result = smRegisterService(&handle, serviceName, false, 1); - bool running = R_FAILED(result); - - svcCloseHandle(handle); - - if (!running) smUnregisterService(serviceName); - - return running; -} - static void retrieveRunningCfwDir() { bool txService = isServiceRunning("tx"); @@ -432,16 +193,6 @@ static void retrieveRunningCfwDir() } } -void delay(u8 seconds) -{ - if (!seconds) return; - - u64 nanoseconds = (seconds * (u64)1000000000); - svcSleepThread(nanoseconds); - - uiRefreshDisplay(); -} - static void createOutputDirectories() { mkdir(HBLOADER_BASE_PATH, 0744); @@ -456,83 +207,6 @@ static void createOutputDirectories() mkdir(TICKET_PATH, 0744); } -static bool getSdCardFreeSpace(u64 *out) -{ - Result result; - FsFileSystem *sdfs = NULL; - u64 size = 0; - - sdfs = fsdevGetDeviceFileSystem("sdmc:"); - if (!sdfs) - { - uiStatusMsg("%s: fsdevGetDefaultFileSystem failed!", __func__); - return false; - } - - result = fsFsGetFreeSpace(sdfs, "/", (s64*)&size); - if (R_FAILED(result)) - { - uiStatusMsg("%s: fsFsGetFreeSpace failed! (0x%08X)", __func__, result); - return false; - } - - *out = size; - - return true; -} - -void convertSize(u64 size, char *out, size_t outSize) -{ - if (!out || !outSize) return; - - double bytes = (double)size; - - if (bytes < 1000.0) - { - snprintf(out, outSize, "%.0lf B", bytes); - } else - if (bytes < (10.0 * KiB)) - { - snprintf(out, outSize, "%.2lf KiB", floor((bytes * 100.0) / KiB) / 100.0); - } else - if (bytes < (100.0 * KiB)) - { - snprintf(out, outSize, "%.1lf KiB", floor((bytes * 10.0) / KiB) / 10.0); - } else - if (bytes < (1000.0 * KiB)) - { - snprintf(out, outSize, "%.0lf KiB", floor(bytes / KiB)); - } else - if (bytes < (10.0 * MiB)) - { - snprintf(out, outSize, "%.2lf MiB", floor((bytes * 100.0) / MiB) / 100.0); - } else - if (bytes < (100.0 * MiB)) - { - snprintf(out, outSize, "%.1lf MiB", floor((bytes * 10.0) / MiB) / 10.0); - } else - if (bytes < (1000.0 * MiB)) - { - snprintf(out, outSize, "%.0lf MiB", floor(bytes / MiB)); - } else - if (bytes < (10.0 * GiB)) - { - snprintf(out, outSize, "%.2lf GiB", floor((bytes * 100.0) / GiB) / 100.0); - } else - if (bytes < (100.0 * GiB)) - { - snprintf(out, outSize, "%.1lf GiB", floor((bytes * 10.0) / GiB) / 10.0); - } else { - snprintf(out, outSize, "%.0lf GiB", floor(bytes / GiB)); - } -} - -void updateFreeSpace() -{ - getSdCardFreeSpace(&freeSpace); - convertSize(freeSpace, freeSpaceStr, MAX_CHARACTERS(freeSpaceStr)); -} - void freeFilenameBuffer(void) { if (!filenameBuffer) return; @@ -578,200 +252,6 @@ static bool addStringToFilenameBuffer(const char *str) return true; } -void initExeFsContext() -{ - memset(&exeFsContext, 0, sizeof(exefs_ctx_t)); -} - -void freeExeFsContext() -{ - if (exeFsContext.storageId == NcmStorageId_GameCard) closeGameCardStoragePartition(); - exeFsContext.storageId = NcmStorageId_None; - - // Remember to close this NCM service resource - ncmContentStorageClose(&(exeFsContext.ncmStorage)); - memset(&(exeFsContext.ncmStorage), 0, sizeof(NcmContentStorage)); - - if (exeFsContext.exefs_entries != NULL) - { - free(exeFsContext.exefs_entries); - exeFsContext.exefs_entries = NULL; - } - - if (exeFsContext.exefs_str_table != NULL) - { - free(exeFsContext.exefs_str_table); - exeFsContext.exefs_str_table = NULL; - } -} - -void initRomFsContext() -{ - memset(&romFsContext, 0, sizeof(romfs_ctx_t)); -} - -void freeRomFsContext() -{ - if (romFsContext.storageId == NcmStorageId_GameCard) closeGameCardStoragePartition(); - romFsContext.storageId = NcmStorageId_None; - - // Remember to close this NCM service resource - ncmContentStorageClose(&(romFsContext.ncmStorage)); - memset(&(romFsContext.ncmStorage), 0, sizeof(NcmContentStorage)); - - if (romFsContext.romfs_dir_entries != NULL) - { - free(romFsContext.romfs_dir_entries); - romFsContext.romfs_dir_entries = NULL; - } - - if (romFsContext.romfs_file_entries != NULL) - { - free(romFsContext.romfs_file_entries); - romFsContext.romfs_file_entries = NULL; - } -} - -void initBktrContext() -{ - memset(&bktrContext, 0, sizeof(bktr_ctx_t)); -} - -void freeBktrContext() -{ - if (bktrContext.storageId == NcmStorageId_GameCard) closeGameCardStoragePartition(); - bktrContext.storageId = NcmStorageId_None; - - // Remember to close this NCM service resource - ncmContentStorageClose(&(bktrContext.ncmStorage)); - memset(&(bktrContext.ncmStorage), 0, sizeof(NcmContentStorage)); - - if (bktrContext.relocation_block != NULL) - { - free(bktrContext.relocation_block); - bktrContext.relocation_block = NULL; - } - - if (bktrContext.subsection_block != NULL) - { - free(bktrContext.subsection_block); - bktrContext.subsection_block = NULL; - } - - if (bktrContext.romfs_dir_entries != NULL) - { - free(bktrContext.romfs_dir_entries); - bktrContext.romfs_dir_entries = NULL; - } - - if (bktrContext.romfs_file_entries != NULL) - { - free(bktrContext.romfs_file_entries); - bktrContext.romfs_file_entries = NULL; - } - - bktrContext.use_base_romfs = false; -} - -static void freeGameCardInfo() -{ - u32 i; - - memset(&(gameCardInfo.header), 0, sizeof(gamecard_header_t)); - - if (gameCardInfo.rootHfs0Header) - { - free(gameCardInfo.rootHfs0Header); - gameCardInfo.rootHfs0Header = NULL; - } - - if (gameCardInfo.hfs0Partitions) - { - for(i = 0; i < gameCardInfo.hfs0PartitionCnt; i++) - { - if (gameCardInfo.hfs0Partitions[i].header) free(gameCardInfo.hfs0Partitions[i].header); - } - - free(gameCardInfo.hfs0Partitions); - gameCardInfo.hfs0Partitions = NULL; - } - - gameCardInfo.hfs0PartitionCnt = 0; - - gameCardInfo.size = 0; - memset(gameCardInfo.sizeStr, 0, sizeof(gameCardInfo.sizeStr)); - - gameCardInfo.trimmedSize = 0; - memset(gameCardInfo.trimmedSizeStr, 0, sizeof(gameCardInfo.trimmedSizeStr)); - - for(i = 0; i < ISTORAGE_PARTITION_CNT; i++) gameCardInfo.IStoragePartitionSizes[i] = 0; - - gameCardInfo.updateTitleId = 0; - gameCardInfo.updateVersion = 0; - memset(gameCardInfo.updateVersionStr, 0, sizeof(gameCardInfo.updateVersionStr)); - - closeGameCardStoragePartition(); -} - -static void freeOrphanPatchOrAddOnList() -{ - if (orphanEntries != NULL) - { - free(orphanEntries); - orphanEntries = NULL; - } - - orphanEntriesCnt = 0; -} - -static void freeTitleInfo() -{ - u32 i; - - if (baseAppEntries && titleAppCount) - { - for(i = 0; i < titleAppCount; i++) - { - if (baseAppEntries[i].icon) free(baseAppEntries[i].icon); - } - } - - if (baseAppEntries) - { - free(baseAppEntries); - baseAppEntries = NULL; - } - - if (patchEntries) - { - free(patchEntries); - patchEntries = NULL; - } - - if (addOnEntries) - { - free(addOnEntries); - addOnEntries = NULL; - } - - titleAppCount = 0; - titlePatchCount = 0; - titleAddOnCount = 0; - - sdCardTitleAppCount = 0; - sdCardTitlePatchCount = 0; - sdCardTitleAddOnCount = 0; - - emmcTitleAppCount = 0; - emmcTitlePatchCount = 0; - emmcTitleAddOnCount = 0; - - gameCardSdCardEmmcPatchCount = 0; - gameCardSdCardEmmcAddOnCount = 0; - - freeOrphanPatchOrAddOnList(); -} - void freeRomFsBrowserEntries() { if (romFsBrowserEntries != NULL) @@ -790,45 +270,6 @@ void freeHfs0ExeFsEntriesSizes() } } -static void freeGlobalData() -{ - freeGameCardInfo(); - - freeTitleInfo(); - - freeExeFsContext(); - - freeRomFsContext(); - - freeBktrContext(); - - freeRomFsBrowserEntries(); - - freeHfs0ExeFsEntriesSizes(); - - freeFilenameBuffer(); -} - -u64 hidKeysAllDown() -{ - u8 controller; - u64 keysDown = 0; - - for(controller = 0; controller < (u8)CONTROLLER_P1_AUTO; controller++) keysDown |= hidKeysDown((HidControllerID)controller); - - return keysDown; -} - -u64 hidKeysAllHeld() -{ - u8 controller; - u64 keysHeld = 0; - - for(controller = 0; controller < (u8)CONTROLLER_P1_AUTO; controller++) keysHeld |= hidKeysHeld((HidControllerID)controller); - - return keysHeld; -} - void consoleErrorScreen(const char *fmt, ...) { consoleInit(NULL); @@ -855,94 +296,6 @@ void consoleErrorScreen(const char *fmt, ...) consoleExit(NULL); } -static bool initServices() -{ - Result result; - - /* Initialize ncm service */ - result = ncmInitialize(); - if (R_FAILED(result)) - { - consoleErrorScreen("%s: failed to initialize ncm service! (0x%08X)", __func__, result); - return false; - } - - initNcm = true; - - /* Initialize ns service */ - result = nsInitialize(); - if (R_FAILED(result)) - { - consoleErrorScreen("%s: failed to initialize ns service! (0x%08X)", __func__, result); - return false; - } - - initNs = true; - - /* Initialize csrng service */ - result = csrngInitialize(); - if (R_FAILED(result)) - { - consoleErrorScreen("%s: failed to initialize csrng service! (0x%08X)", __func__, result); - return false; - } - - initCsrng = true; - - /* Initialize spl service */ - result = splInitialize(); - if (R_FAILED(result)) - { - consoleErrorScreen("%s: failed to initialize spl service! (0x%08X)", __func__, result); - return false; - } - - initSpl = true; - - /* Initialize pm:dmnt service */ - result = pmdmntInitialize(); - if (R_FAILED(result)) - { - consoleErrorScreen("%s: failed to initialize pm:dmnt service! (0x%08X)", __func__, result); - return false; - } - - initPmdmnt = true; - - /* Initialize pl service */ - result = plInitialize(PlServiceType_User); - if (R_FAILED(result)) - { - consoleErrorScreen("%s: failed to initialize pl service! (0x%08X)", __func__, result); - return false; - } - - initPl = true; - - return true; -} - -static void deinitServices() -{ - /* Denitialize pl service */ - if (initPl) plExit(); - - /* Denitialize pm:dmnt service */ - if (initPmdmnt) pmdmntExit(); - - /* Denitialize spl service */ - if (initSpl) splExit(); - - /* Denitialize csrng service */ - if (initCsrng) csrngExit(); - - /* Denitialize ns service */ - if (initNs) nsExit(); - - /* Denitialize ncm service */ - if (initNcm) ncmExit(); -} - bool initApplicationResources(int argc, char **argv) { Result result = 0; @@ -1135,11 +488,6 @@ void deinitApplicationResources() deinitServices(); } -bool appletModeCheck() -{ - return (programAppletType != AppletType_Application && programAppletType != AppletType_SystemApplication); -} - void appletModeOperationWarning() { if (!appletModeCheck()) return; @@ -1148,21 +496,6 @@ void appletModeOperationWarning() breaks++; } -void changeHomeButtonBlockStatus(bool block) -{ - // Only change HOME button blocking status if we're running as a regular application or a system application, and if it's current blocking status is different than the requested one - if (appletModeCheck() || block == homeBtnBlocked) return; - - if (block) - { - appletBeginBlockingHomeButtonShortAndLongPressed(0); - } else { - appletEndBlockingHomeButtonShortAndLongPressed(); - } - - homeBtnBlocked = block; -} - void formatETAString(u64 curTime, char *out, size_t outSize) { if (!out || !outSize) return; @@ -1199,813 +532,6 @@ void generateSdCardEmmcTitleList() } } -static void convertTitleVersionToDotNotation(u32 titleVersion, u8 *outMajor, u8 *outMinor, u8 *outMicro, u16 *outBugfix) -{ - if (!outMajor || !outMinor || !outMicro || !outBugfix) return; - - *outMajor = (u8)((titleVersion >> 26) & 0x3F); - *outMinor = (u8)((titleVersion >> 20) & 0x3F); - *outMicro = (u8)((titleVersion >> 16) & 0xF); - *outBugfix = (u16)titleVersion; -} - -static void generateVersionDottedStr(u32 titleVersion, char *outBuf, size_t outBufSize) -{ - if (!outBuf || !outBufSize) return; - - u8 major = 0, minor = 0, micro = 0; - u16 bugfix = 0; - - convertTitleVersionToDotNotation(titleVersion, &major, &minor, µ, &bugfix); - snprintf(outBuf, outBufSize, "%u (%u.%u.%u.%u)", titleVersion, major, minor, micro, bugfix); -} - -static bool listTitlesByType(NcmContentMetaDatabase *ncmDb, NcmContentMetaType metaType) -{ - if (!ncmDb || (metaType != NcmContentMetaType_Application && metaType != NcmContentMetaType_Patch && metaType != NcmContentMetaType_AddOnContent)) - { - uiStatusMsg("%s: invalid parameters to list titles by type from storage!", __func__); - return false; - } - - bool success = false, proceed = true, memError = false; - - Result result; - - NcmApplicationContentMetaKey *titleList = NULL, *titleListTmp = NULL; - size_t titleListSize = sizeof(NcmApplicationContentMetaKey); - - u32 i, written = 0, total = 0; - - base_app_ctx_t *tmpAppEntries = NULL; - patch_addon_ctx_t *tmpPatchAddOnEntries = NULL; - - titleList = calloc(1, titleListSize); - if (!titleList) - { - uiStatusMsg("%s: unable to allocate memory for the ApplicationContentMetaKey struct! (meta type: 0x%02X).", __func__, (u8)metaType); - goto out; - } - - result = ncmContentMetaDatabaseListApplication(ncmDb, (s32*)&total, (s32*)&written, titleList, 1, metaType); - if (R_FAILED(result)) - { - uiStatusMsg("%s: ncmContentMetaDatabaseListApplication failed! (0x%08X) (meta type: 0x%02X).", __func__, result, (u8)metaType); - goto out; - } - - if (!written || !total) - { - // There are no titles that match the provided filter in the opened storage device - success = true; - goto out; - } - - if (total > written) - { - titleListSize *= total; - titleListTmp = realloc(titleList, titleListSize); - if (titleListTmp) - { - titleList = titleListTmp; - memset(titleList, 0, titleListSize); - - result = ncmContentMetaDatabaseListApplication(ncmDb, (s32*)&total, (s32*)&written, titleList, (s32)total, metaType); - if (R_SUCCEEDED(result)) - { - if (written != total) - { - uiStatusMsg("%s: title count mismatch in ncmContentMetaDatabaseListApplication! (%u != %u) (meta type: 0x%02X).", __func__, written, total, (u8)metaType); - proceed = false; - } - } else { - uiStatusMsg("%s: ncmContentMetaDatabaseListApplication failed! (0x%08X) (meta type: 0x%02X).", __func__, result, (u8)metaType); - proceed = false; - } - } else { - uiStatusMsg("%s: error reallocating output buffer for ncmContentMetaDatabaseListApplication! (%u %s) (meta type: 0x%02X).", __func__, total, (total == 1 ? "entry" : "entries"), (u8)metaType); - proceed = false; - } - } - - if (!proceed) goto out; - - if (metaType == NcmContentMetaType_Application) - { - // If ptr == NULL, realloc will essentially act as a malloc - tmpAppEntries = realloc(baseAppEntries, (titleAppCount + total) * sizeof(base_app_ctx_t)); - if (tmpAppEntries) - { - baseAppEntries = tmpAppEntries; - tmpAppEntries = NULL; - - memset(baseAppEntries + titleAppCount, 0, total * sizeof(base_app_ctx_t)); - - for(i = 0; i < total; i++) - { - baseAppEntries[titleAppCount + i].titleId = titleList[i].key.id; - baseAppEntries[titleAppCount + i].version = titleList[i].key.version; - baseAppEntries[titleAppCount + i].ncmIndex = i; - generateVersionDottedStr(titleList[i].key.version, baseAppEntries[titleAppCount + i].versionStr, VERSION_STR_LEN); - } - - titleAppCount += total; - - success = true; - } else { - memError = true; - } - } else - if (metaType == NcmContentMetaType_Patch) - { - // If ptr == NULL, realloc will essentially act as a malloc - tmpPatchAddOnEntries = realloc(patchEntries, (titlePatchCount + total) * sizeof(patch_addon_ctx_t)); - if (tmpPatchAddOnEntries) - { - patchEntries = tmpPatchAddOnEntries; - tmpPatchAddOnEntries = NULL; - - memset(patchEntries + titlePatchCount, 0, total * sizeof(patch_addon_ctx_t)); - - for(i = 0; i < total; i++) - { - patchEntries[titlePatchCount + i].titleId = titleList[i].key.id; - patchEntries[titlePatchCount + i].version = titleList[i].key.version; - patchEntries[titlePatchCount + i].ncmIndex = i; - generateVersionDottedStr(titleList[i].key.version, patchEntries[titlePatchCount + i].versionStr, VERSION_STR_LEN); - } - - titlePatchCount += total; - - success = true; - } else { - memError = true; - } - } else - if (metaType == NcmContentMetaType_AddOnContent) - { - // If ptr == NULL, realloc will essentially act as a malloc - tmpPatchAddOnEntries = realloc(addOnEntries, (titleAddOnCount + total) * sizeof(patch_addon_ctx_t)); - if (tmpPatchAddOnEntries) - { - addOnEntries = tmpPatchAddOnEntries; - tmpPatchAddOnEntries = NULL; - - memset(addOnEntries + titleAddOnCount, 0, total * sizeof(patch_addon_ctx_t)); - - for(i = 0; i < total; i++) - { - addOnEntries[titleAddOnCount + i].titleId = titleList[i].key.id; - addOnEntries[titleAddOnCount + i].version = titleList[i].key.version; - addOnEntries[titleAddOnCount + i].ncmIndex = i; - generateVersionDottedStr(titleList[i].key.version, addOnEntries[titleAddOnCount + i].versionStr, VERSION_STR_LEN); - } - - titleAddOnCount += total; - - success = true; - } else { - memError = true; - } - } - -out: - if (memError) uiStatusMsg("%s: failed to reallocate entry buffer! (meta type: 0x%02X).", __func__, (u8)metaType); - - if (titleList) free(titleList); - - return success; -} - -static bool getTitleIDAndVersionList(NcmStorageId storageId, bool loadBaseApps, bool loadPatches, bool loadAddOns) -{ - if ((storageId != NcmStorageId_GameCard && storageId != NcmStorageId_SdCard && storageId != NcmStorageId_BuiltInUser) || (!loadBaseApps && !loadPatches && !loadAddOns)) - { - uiStatusMsg("%s: invalid parameters to retrieve Title ID + version list!", __func__); - return false; - } - - /* Check if the SD card is really mounted */ - if (storageId == NcmStorageId_SdCard && fsdevGetDeviceFileSystem("sdmc:") == NULL) return true; - - bool listApp = false, listPatch = false, listAddOn = false, success = false; - - Result result; - NcmContentMetaDatabase ncmDb; - - u32 i; - u32 curAppCount = titleAppCount, curPatchCount = titlePatchCount, curAddOnCount = titleAddOnCount; - - result = ncmOpenContentMetaDatabase(&ncmDb, storageId); - if (R_FAILED(result)) - { - if (storageId == NcmStorageId_SdCard && result == 0x21005) - { - // If the SD card is mounted, but is isn't currently used by HOS because of some weird reason, just filter this particular error and continue - // This can occur when using the "Nintendo" directory from a different console, or when the "sdmc:/Nintendo/Contents/private" file is corrupted - return true; - } else { - uiStatusMsg("%s: ncmOpenContentMetaDatabase failed for storage ID %u! (0x%08X)", __func__, result, storageId); - return false; - } - } - - if (loadBaseApps) - { - listApp = listTitlesByType(&ncmDb, NcmContentMetaType_Application); - if (listApp && titleAppCount > curAppCount) - { - for(i = curAppCount; i < titleAppCount; i++) baseAppEntries[i].storageId = storageId; - } - } - - if (loadPatches) - { - listPatch = listTitlesByType(&ncmDb, NcmContentMetaType_Patch); - if (listPatch && titlePatchCount > curPatchCount) - { - for(i = curPatchCount; i < titlePatchCount; i++) patchEntries[i].storageId = storageId; - } - } - - if (loadAddOns) - { - listAddOn = listTitlesByType(&ncmDb, NcmContentMetaType_AddOnContent); - if (listAddOn && titleAddOnCount > curAddOnCount) - { - for(i = curAddOnCount; i < titleAddOnCount; i++) addOnEntries[i].storageId = storageId; - } - } - - success = (listApp || listPatch || listAddOn); - - ncmContentMetaDatabaseClose(&ncmDb); - - return success; -} - -bool loadTitlesFromSdCardAndEmmc(NcmContentMetaType metaType) -{ - if (menuType != MENUTYPE_GAMECARD || (metaType != NcmContentMetaType_Patch && metaType != NcmContentMetaType_AddOnContent)) return false; - - if ((metaType == NcmContentMetaType_Patch && gameCardSdCardEmmcPatchCount) || (metaType == NcmContentMetaType_AddOnContent && gameCardSdCardEmmcAddOnCount)) return true; - - u8 i; - u32 curPatchCount = titlePatchCount, curAddOnCount = titleAddOnCount; - - for(i = 0; i < 2; i++) - { - NcmStorageId curStorageId = (i == 0 ? NcmStorageId_SdCard : NcmStorageId_BuiltInUser); - - if (!getTitleIDAndVersionList(curStorageId, false, (metaType == NcmContentMetaType_Patch), (metaType == NcmContentMetaType_AddOnContent))) continue; - - if (metaType == NcmContentMetaType_Patch) - { - if (titlePatchCount > curPatchCount) - { - u32 newPatchCount = (titlePatchCount - curPatchCount); - - gameCardSdCardEmmcPatchCount = newPatchCount; - - if (curStorageId == NcmStorageId_SdCard) - { - sdCardTitlePatchCount = newPatchCount; - } else { - emmcTitlePatchCount = newPatchCount; - } - } - } else - if (metaType == NcmContentMetaType_AddOnContent) - { - if (titleAddOnCount > curAddOnCount) - { - u32 newAddOnCount = (titleAddOnCount - curAddOnCount); - - gameCardSdCardEmmcAddOnCount = newAddOnCount; - - if (curStorageId == NcmStorageId_SdCard) - { - sdCardTitleAddOnCount = newAddOnCount; - } else { - emmcTitleAddOnCount = newAddOnCount; - } - } - } - } - - if ((metaType == NcmContentMetaType_Patch && gameCardSdCardEmmcPatchCount) || (metaType == NcmContentMetaType_AddOnContent && gameCardSdCardEmmcAddOnCount)) return true; - - return false; -} - -void freeTitlesFromSdCardAndEmmc(NcmContentMetaType metaType) -{ - if (menuType != MENUTYPE_GAMECARD || (metaType != NcmContentMetaType_Patch && metaType != NcmContentMetaType_AddOnContent) || (metaType == NcmContentMetaType_Patch && (!titlePatchCount || !gameCardSdCardEmmcPatchCount)) || (metaType == NcmContentMetaType_AddOnContent && (!titleAddOnCount || !gameCardSdCardEmmcAddOnCount))) return; - - patch_addon_ctx_t *tmpPatchAddOnEntries = NULL; - - if (metaType == NcmContentMetaType_Patch) - { - if ((titlePatchCount - gameCardSdCardEmmcPatchCount) > 0) - { - tmpPatchAddOnEntries = realloc(patchEntries, (titlePatchCount - gameCardSdCardEmmcPatchCount) * sizeof(patch_addon_ctx_t)); - if (tmpPatchAddOnEntries != NULL) - { - patchEntries = tmpPatchAddOnEntries; - tmpPatchAddOnEntries = NULL; - } - } else { - free(patchEntries); - patchEntries = NULL; - } - - titlePatchCount -= gameCardSdCardEmmcPatchCount; - - gameCardSdCardEmmcPatchCount = 0; - sdCardTitlePatchCount = 0; - emmcTitlePatchCount = 0; - } else { - if ((titleAddOnCount - gameCardSdCardEmmcAddOnCount) > 0) - { - tmpPatchAddOnEntries = realloc(addOnEntries, (titleAddOnCount - gameCardSdCardEmmcAddOnCount) * sizeof(patch_addon_ctx_t)); - if (tmpPatchAddOnEntries != NULL) - { - addOnEntries = tmpPatchAddOnEntries; - tmpPatchAddOnEntries = NULL; - } - } else { - free(addOnEntries); - addOnEntries = NULL; - } - - titleAddOnCount -= gameCardSdCardEmmcAddOnCount; - - gameCardSdCardEmmcAddOnCount = 0; - sdCardTitleAddOnCount = 0; - emmcTitleAddOnCount = 0; - } -} - -static bool getCachedBaseApplicationNacpMetadata(u64 titleID, char *nameBuf, size_t nameBufSize, char *authorBuf, size_t authorBufSize, u8 **iconBuf) -{ - // At least the name must be retrieved - if (!nameBuf || !nameBufSize || (authorBuf && !authorBufSize)) - { - uiStatusMsg("%s: invalid parameters to retrieve Control.nacp!", __func__); - return false; - } - - bool getNameAndAuthor = false, getIcon = false, success = false; - Result result; - size_t outsize = 0; - NsApplicationControlData *buf = NULL; - NacpLanguageEntry *langentry = NULL; - - buf = calloc(1, sizeof(NsApplicationControlData)); - if (buf) - { - result = nsGetApplicationControlData(NsApplicationControlSource_Storage, titleID, buf, sizeof(NsApplicationControlData), &outsize); - if (R_SUCCEEDED(result)) - { - if (outsize >= sizeof(buf->nacp)) - { - result = nacpGetLanguageEntry(&buf->nacp, &langentry); - if (R_SUCCEEDED(result)) - { - snprintf(nameBuf, nameBufSize, langentry->name); - if (authorBuf && authorBufSize) snprintf(authorBuf, authorBufSize, langentry->author); - getNameAndAuthor = true; - } else { - uiStatusMsg("%s: GetLanguageEntry failed! (0x%08X)", __func__, result); - } - - if (iconBuf != NULL) - { - getIcon = uiLoadJpgFromMem(buf->icon, sizeof(buf->icon), NACP_ICON_SQUARE_DIMENSION, NACP_ICON_SQUARE_DIMENSION, NACP_ICON_DOWNSCALED, NACP_ICON_DOWNSCALED, iconBuf); - if (!getIcon) uiStatusMsg(strbuf); - } - - success = (iconBuf != NULL ? (getNameAndAuthor && getIcon) : getNameAndAuthor); - } else { - uiStatusMsg("%s: Control.nacp buffer size (%u bytes) is too small! Expected: %u bytes", __func__, outsize, sizeof(buf->nacp)); - } - } else { - uiStatusMsg("%s: GetApplicationControlData failed! (0x%08X)", __func__, result); - } - - free(buf); - } else { - uiStatusMsg("%s: unable to allocate memory for the ns service operations!", __func__); - } - - return success; -} - -void removeIllegalCharacters(char *name) -{ - if (!name || !strlen(name)) return; - - u32 i, len = strlen(name); - for (i = 0; i < len; i++) - { - if (memchr("?[]/\\=+<>:;\",*|^", name[i], sizeof("?[]/\\=+<>:;\",*|^") - 1) || name[i] < 0x20 || name[i] > 0x7E) name[i] = '_'; - } -} - -void strtrim(char *str) -{ - if (!str || !strlen(str)) return; - - char *start = str; - char *end = (start + strlen(str)); - - while(--end >= start) - { - if (!isspace((unsigned char)*end)) break; - } - - *(++end) = '\0'; - - while(isspace((unsigned char)*start)) start++; - - if (start != str) memmove(str, start, end - start + 1); -} - -bool retrieveGameCardInfo() -{ - Result result; - bool success = false; - - u32 i; - hfs0_header header; - hfs0_file_entry entry; - - u8 major = 0, minor = 0, micro = 0; - u16 bugfix = 0; - - // Open normal IStorage partition - result = openGameCardStoragePartition(ISTORAGE_PARTITION_NORMAL); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to open normal IStorage partition! (0x%08X)", __func__, result); - return false; - } - - // Retrieve normal IStorage partition size - result = getGameCardStoragePartitionSize(&(gameCardInfo.IStoragePartitionSizes[0])); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to retrieve size for normal IStorage partition! (0x%08X)", __func__, result); - return false; - } - - // Read gamecard header - result = readGameCardStoragePartition(0, &(gameCardInfo.header), sizeof(gamecard_header_t)); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to read %lu bytes long gamecard header! (0x%08X)", __func__, sizeof(gamecard_header_t), result); - goto out; - } - - if (__builtin_bswap32(gameCardInfo.header.magic) != GAMECARD_HEADER_MAGIC) - { - uiStatusMsg("%s: invalid gamecard header magic word! (0x%08X)", __func__, __builtin_bswap32(gameCardInfo.header.magic)); - goto out; - } - - switch(gameCardInfo.header.size) - { - case 0xFA: // 1 GiB - gameCardInfo.size = GAMECARD_SIZE_1GiB; - break; - case 0xF8: // 2 GiB - gameCardInfo.size = GAMECARD_SIZE_2GiB; - break; - case 0xF0: // 4 GiB - gameCardInfo.size = GAMECARD_SIZE_4GiB; - break; - case 0xE0: // 8 GiB - gameCardInfo.size = GAMECARD_SIZE_8GiB; - break; - case 0xE1: // 16 GiB - gameCardInfo.size = GAMECARD_SIZE_16GiB; - break; - case 0xE2: // 32 GiB - gameCardInfo.size = GAMECARD_SIZE_32GiB; - break; - default: - uiStatusMsg("%s: invalid gamecard size value! (0x%02X)", __func__, gameCardInfo.header.size); - goto out; - } - - convertSize(gameCardInfo.size, gameCardInfo.sizeStr, MAX_CHARACTERS(gameCardInfo.sizeStr)); - - gameCardInfo.trimmedSize = (sizeof(gamecard_header_t) + (gameCardInfo.header.validDataEndAddr * MEDIA_UNIT_SIZE)); - convertSize(gameCardInfo.trimmedSize, gameCardInfo.trimmedSizeStr, MAX_CHARACTERS(gameCardInfo.trimmedSizeStr)); - - gameCardInfo.rootHfs0Header = calloc(1, gameCardInfo.header.rootHfs0HeaderSize); - if (!gameCardInfo.rootHfs0Header) - { - uiStatusMsg("%s: unable to allocate memory for the root HFS0 header!", __func__); - goto out; - } - - result = readGameCardStoragePartition(gameCardInfo.header.rootHfs0HeaderOffset, gameCardInfo.rootHfs0Header, gameCardInfo.header.rootHfs0HeaderSize); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to read %lu bytes long root HFS0 header! (0x%08X)", __func__, gameCardInfo.header.rootHfs0HeaderSize, result); - goto out; - } - - memcpy(&header, gameCardInfo.rootHfs0Header, sizeof(hfs0_header)); - - if (__builtin_bswap32(header.magic) != HFS0_MAGIC) - { - uiStatusMsg("%s: invalid magic word in root HFS0 header! (0x%08X)", __func__, __builtin_bswap32(header.magic)); - goto out; - } - - if (!header.file_cnt) - { - uiStatusMsg("%s: invalid file count in root HFS0 header!", __func__); - goto out; - } - - if (!header.str_table_size) - { - uiStatusMsg("%s: invalid string table size in root HFS0 header!", __func__); - goto out; - } - - gameCardInfo.hfs0PartitionCnt = header.file_cnt; - - // Retrieve partition data - gameCardInfo.hfs0Partitions = calloc(gameCardInfo.hfs0PartitionCnt, sizeof(hfs0_partition_info)); - if (!gameCardInfo.hfs0Partitions) - { - uiStatusMsg("%s: unable to allocate memory for HFS0 partition headers!", __func__); - goto out; - } - - for(i = 0; i < gameCardInfo.hfs0PartitionCnt; i++) - { - memcpy(&entry, gameCardInfo.rootHfs0Header + sizeof(hfs0_header) + (i * sizeof(hfs0_file_entry)), sizeof(hfs0_file_entry)); - - if (!entry.file_size) - { - uiStatusMsg("%s: invalid size for %s HFS0 partition!", __func__, GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, i)); - goto out; - } - - gameCardInfo.hfs0Partitions[i].size = entry.file_size; - - // Check if we're dealing with the secure HFS0 partition - if (i == (gameCardInfo.hfs0PartitionCnt - 1)) - { - // The partition offset must be zero, because the secure HFS0 partition is stored at the start of the secure IStorage partition - gameCardInfo.hfs0Partitions[i].offset = 0; - - // Open secure IStorage partition - result = openGameCardStoragePartition(ISTORAGE_PARTITION_SECURE); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to open secure IStorage partition! (0x%08X)", __func__, result); - goto out; - } - - if (strncmp(cfwDirStr, CFW_PATH_SXOS, strlen(CFW_PATH_SXOS)) != 0) - { - // Retrieve secure IStorage partition size - result = getGameCardStoragePartitionSize(&(gameCardInfo.IStoragePartitionSizes[1])); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to retrieve size for secure IStorage partition! (0x%08X)", __func__, result); - goto out; - } - } else { - // Total size for the secure IStorage partition is maxed out under SX OS, so let's try to calculate it manually - gameCardInfo.IStoragePartitionSizes[1] = ((gameCardInfo.size - ((gameCardInfo.size / GAMECARD_ECC_BLOCK_SIZE) * GAMECARD_ECC_DATA_SIZE)) - gameCardInfo.IStoragePartitionSizes[0]); - } - } else { - // The partition offset is relative to the start of the normal IStorage partition (true gamecard image start) - gameCardInfo.hfs0Partitions[i].offset = (gameCardInfo.header.rootHfs0HeaderOffset + gameCardInfo.header.rootHfs0HeaderSize + entry.file_offset); - } - - // Partially read the current HFS0 partition header - result = readGameCardStoragePartition(gameCardInfo.hfs0Partitions[i].offset, &header, sizeof(hfs0_header)); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to read %lu bytes long chunk from %s HFS0 partition! (0x%08X)", __func__, sizeof(hfs0_header), GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, i), result); - goto out; - } - - // Check the HFS0 magic word - if (__builtin_bswap32(header.magic) != HFS0_MAGIC) - { - uiStatusMsg("%s: invalid magic word in %s HFS0 partition header! (0x%08X)", __func__, GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, i), __builtin_bswap32(header.magic)); - goto out; - } - - if (!header.str_table_size) - { - uiStatusMsg("%s: invalid string table size in %s HFS0 partition header!", __func__, GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, i)); - goto out; - } - - // Calculate the size for the HFS0 partition header and round it to a MEDIA_UNIT_SIZE bytes boundary - gameCardInfo.hfs0Partitions[i].header_size = (sizeof(hfs0_header) + (header.file_cnt * sizeof(hfs0_file_entry)) + header.str_table_size); - gameCardInfo.hfs0Partitions[i].header_size = round_up(gameCardInfo.hfs0Partitions[i].header_size, MEDIA_UNIT_SIZE); - - gameCardInfo.hfs0Partitions[i].file_cnt = header.file_cnt; - gameCardInfo.hfs0Partitions[i].str_table_size = header.str_table_size; - - gameCardInfo.hfs0Partitions[i].header = calloc(1, gameCardInfo.hfs0Partitions[i].header_size); - if (!gameCardInfo.hfs0Partitions[i].header) - { - uiStatusMsg("%s: unable to allocate memory for %s HFS0 partition header!", __func__, GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, i)); - goto out; - } - - // Finally, read the full HFS0 partition header - result = readGameCardStoragePartition(gameCardInfo.hfs0Partitions[i].offset, gameCardInfo.hfs0Partitions[i].header, gameCardInfo.hfs0Partitions[i].header_size); - if (R_FAILED(result)) - { - uiStatusMsg("%s: failed to read %lu bytes long %s HFS0 partition header! (0x%08X)", __func__, gameCardInfo.hfs0Partitions[i].header_size, GAMECARD_PARTITION_NAME(gameCardInfo.hfs0PartitionCnt, i), result); - goto out; - } - } - - // Get bundled FW version update - result = fsDeviceOperatorUpdatePartitionInfo(&(gameCardInfo.fsOperatorInstance), &(gameCardInfo.fsGameCardHandle), &(gameCardInfo.updateVersion), &(gameCardInfo.updateTitleId)); - if (R_SUCCEEDED(result)) - { - if (gameCardInfo.updateTitleId == GAMECARD_UPDATE_TITLEID) - { - convertTitleVersionToDotNotation(gameCardInfo.updateVersion, &major, &minor, µ, &bugfix); - snprintf(gameCardInfo.updateVersionStr, MAX_CHARACTERS(gameCardInfo.updateVersionStr), "%u.%u.%u (v%u)", major, minor, micro, gameCardInfo.updateVersion); - } else { - uiStatusMsg("%s: update Title ID mismatch! (%016lX != %016lX)", __func__, gameCardInfo.updateTitleId, GAMECARD_UPDATE_TITLEID); - } - } else { - uiStatusMsg("%s: UpdatePartitionInfo failed! (0x%08X)", __func__, result); - } - - success = true; - -out: - if (success) - { - closeGameCardStoragePartition(); - } else { - freeGameCardInfo(); - } - - return success; -} - -u64 calculateSizeFromContentRecords(NcmStorageId curStorageId, NcmContentMetaType metaType, u32 ncmTitleCount, u32 ncmTitleIndex) -{ - if ((curStorageId != NcmStorageId_GameCard && curStorageId != NcmStorageId_SdCard && curStorageId != NcmStorageId_BuiltInUser) || (metaType != NcmContentMetaType_Application && metaType != NcmContentMetaType_Patch && metaType != NcmContentMetaType_AddOnContent) || ncmTitleIndex >= ncmTitleCount) return 0; - - NcmContentInfo *titleContentInfos = NULL; - u32 i, titleContentInfoCnt = 0; - u64 tmp = 0, outSize = 0; - - if (!retrieveContentInfosFromTitle(curStorageId, metaType, ncmTitleCount, ncmTitleIndex, &titleContentInfos, &titleContentInfoCnt)) return 0; - - for(i = 0; i < titleContentInfoCnt; i++) - { - if (titleContentInfos[i].content_type >= NcmContentType_DeltaFragment) continue; - - convertNcaSizeToU64(titleContentInfos[i].size, &tmp); - outSize += tmp; - } - - free(titleContentInfos); - - return outSize; -} - -int baseAppCmp(const void *a, const void *b) -{ - base_app_ctx_t *baseApp1 = (base_app_ctx_t*)a; - base_app_ctx_t *baseApp2 = (base_app_ctx_t*)b; - - return strcasecmp(baseApp1->name, baseApp2->name); -} - -int orphanEntryCmp(const void *a, const void *b) -{ - orphan_patch_addon_entry *orphanEntry1 = (orphan_patch_addon_entry*)a; - orphan_patch_addon_entry *orphanEntry2 = (orphan_patch_addon_entry*)b; - - return strcasecmp(orphanEntry1->orphanListStr, orphanEntry2->orphanListStr); -} - -void loadTitleInfo() -{ - if (menuType == MENUTYPE_MAIN) - { - freeGlobalData(); - changeAtomicBool(&gameCardInfoLoaded, false); - sdCardAndEmmcTitleInfoLoaded = false; - return; - } - - bool proceed = false; - - if (menuType == MENUTYPE_GAMECARD) - { - if (gameCardInfo.isInserted && gameCardInfoLoaded) return; - - freeGlobalData(); - - if (!gameCardInfo.isInserted) return; - - /* Don't access the gamecard immediately to avoid conflicts with the fsp-srv, ncm and ns services */ - uiPleaseWait(GAMECARD_WAIT_TIME); - - proceed = retrieveGameCardInfo(); - changeAtomicBool(&gameCardInfoLoaded, true); - - if (proceed) proceed = getTitleIDAndVersionList(NcmStorageId_GameCard, true, true, true); - } else - if (menuType == MENUTYPE_SDCARD_EMMC) - { - if (sdCardAndEmmcTitleInfoLoaded) return; - - uiPleaseWait(0); - - freeTitleInfo(); - - if (getTitleIDAndVersionList(NcmStorageId_SdCard, true, true, true)) - { - sdCardTitleAppCount = titleAppCount; - sdCardTitlePatchCount = titlePatchCount; - sdCardTitleAddOnCount = titleAddOnCount; - - if (getTitleIDAndVersionList(NcmStorageId_BuiltInUser, true, true, true)) - { - emmcTitleAppCount = (titleAppCount - sdCardTitleAppCount); - emmcTitlePatchCount = (titlePatchCount - sdCardTitlePatchCount); - emmcTitleAddOnCount = (titleAddOnCount - sdCardTitleAddOnCount); - - proceed = true; - } - } - - sdCardAndEmmcTitleInfoLoaded = true; - } - - if (proceed) - { - u32 i, ncmTitleCount; - - for(i = 0; i < titleAppCount; i++) - { - // Retrieve base application name, author and icon - if (getCachedBaseApplicationNacpMetadata(baseAppEntries[i].titleId, baseAppEntries[i].name, MAX_CHARACTERS(baseAppEntries[i].name), baseAppEntries[i].author, MAX_CHARACTERS(baseAppEntries[i].author), &(baseAppEntries[i].icon))) - { - strtrim(baseAppEntries[i].name); - strtrim(baseAppEntries[i].author); - snprintf(baseAppEntries[i].fixedName, MAX_CHARACTERS(baseAppEntries[i].fixedName), baseAppEntries[i].name); - removeIllegalCharacters(baseAppEntries[i].fixedName); - } - - // Retrieve base application content size - ncmTitleCount = (baseAppEntries[i].storageId == NcmStorageId_GameCard ? titleAppCount : (baseAppEntries[i].storageId == NcmStorageId_SdCard ? sdCardTitleAppCount : emmcTitleAppCount)); - baseAppEntries[i].contentSize = calculateSizeFromContentRecords(baseAppEntries[i].storageId, NcmContentMetaType_Application, ncmTitleCount, baseAppEntries[i].ncmIndex); - convertSize(baseAppEntries[i].contentSize, baseAppEntries[i].contentSizeStr, MAX_CHARACTERS(baseAppEntries[i].contentSizeStr)); - } - - // Sort base applications by name - if (titleAppCount) qsort(baseAppEntries, titleAppCount, sizeof(base_app_ctx_t), baseAppCmp); - - for(i = 0; i < titlePatchCount; i++) - { - // Retrieve patch content size - ncmTitleCount = (patchEntries[i].storageId == NcmStorageId_GameCard ? titlePatchCount : (patchEntries[i].storageId == NcmStorageId_SdCard ? sdCardTitlePatchCount : emmcTitlePatchCount)); - patchEntries[i].contentSize = calculateSizeFromContentRecords(patchEntries[i].storageId, NcmContentMetaType_Patch, ncmTitleCount, patchEntries[i].ncmIndex); - convertSize(patchEntries[i].contentSize, patchEntries[i].contentSizeStr, MAX_CHARACTERS(patchEntries[i].contentSizeStr)); - } - - for(i = 0; i < titleAddOnCount; i++) - { - // Retrieve add-on content size - ncmTitleCount = (addOnEntries[i].storageId == NcmStorageId_GameCard ? titleAddOnCount : (addOnEntries[i].storageId == NcmStorageId_SdCard ? sdCardTitleAddOnCount : emmcTitleAddOnCount)); - addOnEntries[i].contentSize = calculateSizeFromContentRecords(addOnEntries[i].storageId, NcmContentMetaType_AddOnContent, ncmTitleCount, addOnEntries[i].ncmIndex); - convertSize(addOnEntries[i].contentSize, addOnEntries[i].contentSizeStr, MAX_CHARACTERS(addOnEntries[i].contentSizeStr)); - } - - // Generate orphan content list - // If orphanEntries == NULL or if orphanEntriesCnt == 0, both variables will be regenerated - // Otherwise, this will only fill filenameBuffer - if (menuType == MENUTYPE_SDCARD_EMMC) generateOrphanPatchOrAddOnList(); - } - - uiPrintHeadline(); -} - void truncateBrowserEntryName(char *str) { if (!str || !strlen(str)) return; @@ -2096,317 +622,6 @@ bool getHfs0FileList(u32 partition) return true; } -// Used to retrieve data from files in the HFS0 Secure partition -// An IStorage instance must have been opened beforehand -bool readFileFromSecureHfs0PartitionByName(const char *filename, u64 offset, void *outBuf, size_t bufSize) -{ - if (!gameCardInfo.hfs0PartitionCnt || !gameCardInfo.hfs0Partitions || !gameCardInfo.hfs0Partitions[gameCardInfo.hfs0PartitionCnt - 1].header || !gameCardInfo.hfs0Partitions[gameCardInfo.hfs0PartitionCnt - 1].header_size || !gameCardInfo.hfs0Partitions[gameCardInfo.hfs0PartitionCnt - 1].file_cnt || !gameCardInfo.hfs0Partitions[gameCardInfo.hfs0PartitionCnt - 1].str_table_size || !filename || !strlen(filename) || !outBuf || !bufSize) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to read file from Secure HFS0 partition!", __func__); - return false; - } - - u32 i; - Result result; - hfs0_file_entry entry; - - bool proceed = true, found = false; - - u32 partition = (gameCardInfo.hfs0PartitionCnt - 1); // Select the Secure HFS0 partition - - for(i = 0; i < gameCardInfo.hfs0Partitions[partition].file_cnt; i++) - { - memcpy(&entry, gameCardInfo.hfs0Partitions[partition].header + sizeof(hfs0_header) + (i * sizeof(hfs0_file_entry)), sizeof(hfs0_file_entry)); - - char *cur_filename = (char*)(gameCardInfo.hfs0Partitions[partition].header + sizeof(hfs0_header) + (gameCardInfo.hfs0Partitions[partition].file_cnt * sizeof(hfs0_file_entry)) + entry.filename_offset); - - if (strncasecmp(cur_filename, filename, strlen(filename)) != 0) continue; - - found = true; - - if (!entry.file_size || (offset + bufSize) > entry.file_size) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid file size for \"%s\"!", __func__, filename); - proceed = false; - } - - break; - } - - if (!proceed || !found) - { - if (proceed && !found) uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: unable to find file \"%s\" in Secure HFS0 partition!", __func__, filename); - return false; - } - - result = readGameCardStoragePartition(gameCardInfo.hfs0Partitions[partition].header_size + entry.file_offset + offset, outBuf, bufSize); - if (R_FAILED(result)) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: failed to read file \"%s\"! (0x%08X)", __func__, filename, result); - return false; - } - - return true; -} - -bool calculateExeFsExtractedDataSize(u64 *out) -{ - if (!exeFsContext.exefs_header.file_cnt || !exeFsContext.exefs_entries || !out) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to calculate extracted data size for the ExeFS section!", __func__); - return false; - } - - u32 i; - u64 totalSize = 0; - - for(i = 0; i < exeFsContext.exefs_header.file_cnt; i++) totalSize += exeFsContext.exefs_entries[i].file_size; - - *out = totalSize; - - return true; -} - -bool calculateRomFsFullExtractedSize(bool usePatch, u64 *out) -{ - if ((!usePatch && (!romFsContext.romfs_filetable_size || !romFsContext.romfs_file_entries)) || (usePatch && (!bktrContext.romfs_filetable_size || !bktrContext.romfs_file_entries)) || !out) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to calculate extracted data size for the RomFS section!", __func__); - return false; - } - - u64 offset = 0; - u64 totalSize = 0; - - u64 filetableSize = (!usePatch ? romFsContext.romfs_filetable_size : bktrContext.romfs_filetable_size); - romfs_file *fileEntries = (!usePatch ? romFsContext.romfs_file_entries : bktrContext.romfs_file_entries); - - while(offset < filetableSize) - { - romfs_file *entry = (romfs_file*)((u8*)fileEntries + offset); - - totalSize += entry->dataSize; - - offset += round_up(ROMFS_NONAME_FILEENTRY_SIZE + entry->nameLen, 4); - } - - *out = totalSize; - - return true; -} - -bool calculateRomFsExtractedDirSize(u32 dir_offset, bool usePatch, u64 *out) -{ - if ((!usePatch && (!romFsContext.romfs_dirtable_size || !romFsContext.romfs_dir_entries || !romFsContext.romfs_filetable_size || !romFsContext.romfs_file_entries || dir_offset > romFsContext.romfs_dirtable_size)) || (usePatch && (!bktrContext.romfs_dirtable_size || !bktrContext.romfs_dir_entries || !bktrContext.romfs_filetable_size || !bktrContext.romfs_file_entries || dir_offset > bktrContext.romfs_dirtable_size)) || !out) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: invalid parameters to calculate extracted size for the current RomFS directory!", __func__); - return false; - } - - u64 totalSize = 0, childDirSize = 0; - romfs_file *fileEntry = NULL; - romfs_dir *childDirEntry = NULL; - romfs_dir *dirEntry = (!usePatch ? (romfs_dir*)((u8*)romFsContext.romfs_dir_entries + dir_offset) : (romfs_dir*)((u8*)bktrContext.romfs_dir_entries + dir_offset)); - - // Check if we're dealing with a nameless directory that's not the root directory - if (!dirEntry->nameLen && dir_offset > 0) - { - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_ERROR_RGB, "%s: directory entry without name in RomFS section!", __func__); - return false; - } - - if (dirEntry->childFile != ROMFS_ENTRY_EMPTY) - { - fileEntry = (!usePatch ? (romfs_file*)((u8*)romFsContext.romfs_file_entries + dirEntry->childFile) : (romfs_file*)((u8*)bktrContext.romfs_file_entries + dirEntry->childFile)); - - totalSize += fileEntry->dataSize; - - while(fileEntry->sibling != ROMFS_ENTRY_EMPTY) - { - fileEntry = (!usePatch ? (romfs_file*)((u8*)romFsContext.romfs_file_entries + fileEntry->sibling) : (romfs_file*)((u8*)bktrContext.romfs_file_entries + fileEntry->sibling)); - - totalSize += fileEntry->dataSize; - } - } - - if (dirEntry->childDir != ROMFS_ENTRY_EMPTY) - { - if (!calculateRomFsExtractedDirSize(dirEntry->childDir, usePatch, &childDirSize)) return false; - - totalSize += childDirSize; - - childDirEntry = (!usePatch ? (romfs_dir*)((u8*)romFsContext.romfs_dir_entries + dirEntry->childDir) : (romfs_dir*)((u8*)bktrContext.romfs_dir_entries + dirEntry->childDir)); - - while(childDirEntry->sibling != ROMFS_ENTRY_EMPTY) - { - if (!calculateRomFsExtractedDirSize(childDirEntry->sibling, usePatch, &childDirSize)) return false; - - totalSize += childDirSize; - - childDirEntry = (!usePatch ? (romfs_dir*)((u8*)romFsContext.romfs_dir_entries + childDirEntry->sibling) : (romfs_dir*)((u8*)bktrContext.romfs_dir_entries + childDirEntry->sibling)); - } - } - - *out = totalSize; - - return true; -} - -bool retrieveContentInfosFromTitle(NcmStorageId storageId, NcmContentMetaType metaType, u32 titleCount, u32 titleIndex, NcmContentInfo **outContentInfos, u32 *outContentInfoCnt) -{ - Result result; - - NcmContentMetaDatabase ncmDb; - memset(&ncmDb, 0, sizeof(NcmContentMetaDatabase)); - - NcmContentMetaHeader cnmtHeader; - memset(&cnmtHeader, 0, sizeof(NcmContentMetaHeader)); - u64 cnmtHeaderReadSize = 0; - - NcmApplicationContentMetaKey *titleList = NULL; - size_t titleListSize = (sizeof(NcmApplicationContentMetaKey) * titleCount); - - NcmContentInfo *titleContentInfos = NULL; - u32 titleContentInfoCnt = 0; - - u32 written = 0, total = 0; - - bool success = false; - - if (storageId != NcmStorageId_GameCard && storageId != NcmStorageId_SdCard && storageId != NcmStorageId_BuiltInUser) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: invalid title storage ID!", __func__); - goto out; - } - - if (metaType != NcmContentMetaType_Application && metaType != NcmContentMetaType_Patch && metaType != NcmContentMetaType_AddOnContent) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: invalid title meta type!", __func__); - goto out; - } - - if (!titleCount) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: invalid title type count!", __func__); - goto out; - } - - if (titleIndex >= titleCount) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: invalid title index!", __func__); - goto out; - } - - if (!outContentInfos || !outContentInfoCnt) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: invalid output parameters!", __func__); - goto out; - } - - titleList = calloc(1, titleListSize); - if (!titleList) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: unable to allocate memory for the ApplicationContentMetaKey struct!", __func__); - goto out; - } - - result = ncmOpenContentMetaDatabase(&ncmDb, storageId); - if (R_FAILED(result)) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: ncmOpenContentMetaDatabase failed! (0x%08X)", __func__, result); - goto out; - } - - result = ncmContentMetaDatabaseListApplication(&ncmDb, (s32*)&total, (s32*)&written, titleList, (s32)titleCount, metaType); - if (R_FAILED(result)) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: ncmContentMetaDatabaseListApplication failed! (0x%08X)", __func__, result); - goto out; - } - - if (!written || !total) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: ncmContentMetaDatabaseListApplication wrote no entries to output buffer!", __func__); - goto out; - } - - if (written != total) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: title count mismatch in ncmContentMetaDatabaseListApplication! (%u != %u)", __func__, written, total); - goto out; - } - - if (titleIndex >= total) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: provided title index exceeds title count from ncmContentMetaDatabaseListApplication!", __func__); - goto out; - } - - result = ncmContentMetaDatabaseGet(&ncmDb, &(titleList[titleIndex].key), &cnmtHeaderReadSize, &cnmtHeader, sizeof(NcmContentMetaHeader)); - if (R_FAILED(result)) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: ncmContentMetaDatabaseGet failed! (0x%08X)", __func__, result); - goto out; - } - - titleContentInfoCnt = (u32)(cnmtHeader.content_count); - - titleContentInfos = calloc(titleContentInfoCnt, sizeof(NcmContentInfo)); - if (!titleContentInfos) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: unable to allocate memory for the title content information struct!", __func__); - goto out; - } - - written = 0; - - result = ncmContentMetaDatabaseListContentInfo(&ncmDb, (s32*)&written, titleContentInfos, (s32)titleContentInfoCnt, &(titleList[titleIndex].key), 0); - if (R_FAILED(result)) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: ncmContentMetaDatabaseListContentInfo failed! (0x%08X)", __func__, result); - goto out; - } - - if (written != titleContentInfoCnt) - { - snprintf(strbuf, MAX_CHARACTERS(strbuf), "%s: title content count mismatch in ncmContentMetaDatabaseListContentInfo! (%u != %u)", __func__, written, titleContentInfoCnt); - goto out; - } - - success = true; - - // Update output parameters - *outContentInfos = titleContentInfos; - *outContentInfoCnt = titleContentInfoCnt; - -out: - if (!success && titleContentInfos) free(titleContentInfos); - - ncmContentMetaDatabaseClose(&ncmDb); - - if (titleList) free(titleList); - - return success; -} - -void removeConsoleDataFromTicket(title_rights_ctx *rights_info) -{ - if (!rights_info || !rights_info->has_rights_id || !rights_info->retrieved_tik || rights_info->missing_tik || rights_info->tik_data.titlekey_type != ETICKET_TITLEKEY_PERSONALIZED) return; - - memset(rights_info->tik_data.signature, 0xFF, 0x100); - - memset(rights_info->tik_data.sig_issuer, 0, 0x40); - sprintf(rights_info->tik_data.sig_issuer, "Root-CA00000003-XS00000020"); - - memset(rights_info->tik_data.titlekey_block, 0, 0x100); - memcpy(rights_info->tik_data.titlekey_block, rights_info->enc_titlekey, 0x10); - - rights_info->tik_data.titlekey_type = ETICKET_TITLEKEY_COMMON; - rights_info->tik_data.ticket_id = 0; - rights_info->tik_data.device_id = 0; - rights_info->tik_data.account_id = 0; -} - bool listDesiredNcaType(NcmContentInfo *titleContentInfos, u32 titleContentInfoCnt, u8 type, int desiredIdOffset, u32 *outIndex, u32 *outCount) { if (!titleContentInfos || !titleContentInfoCnt || type > NcmContentType_DeltaFragment || !outIndex || !outCount) @@ -3215,472 +1430,6 @@ out: return true; } -char *generateGameCardDumpName(bool useBrackets) -{ - if (menuType != MENUTYPE_GAMECARD || !titleAppCount || !baseAppEntries) return NULL; - - u32 i, j; - - char tmp[NAME_BUF_LEN / 2] = {'\0'}; - char *fullname = NULL; - char *fullnameTmp = NULL; - - size_t strsize = NAME_BUF_LEN; - - fullname = calloc(strsize + 1, sizeof(char)); - if (!fullname) return NULL; - - for(i = 0; i < titleAppCount; i++) - { - u32 highestVersion = baseAppEntries[i].version; - - // Check if our current gamecard has any bundled updates for this application. If so, use the highest update version available - if (titlePatchCount && patchEntries) - { - for(j = 0; j < titlePatchCount; j++) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(j, i, false) && patchEntries[j].version > highestVersion) highestVersion = patchEntries[j].version; - } - } - - if (useBrackets) - { - snprintf(tmp, MAX_CHARACTERS(tmp), "%s [%016lX][v%u]", baseAppEntries[i].fixedName, baseAppEntries[i].titleId, highestVersion); - } else { - snprintf(tmp, MAX_CHARACTERS(tmp), "%s v%u (%016lX)", baseAppEntries[i].fixedName, highestVersion, baseAppEntries[i].titleId); - } - - if ((strlen(fullname) + strlen(tmp) + 4) > strsize) - { - size_t fullname_len = strlen(fullname); - - strsize = (fullname_len + strlen(tmp) + 4); - - fullnameTmp = realloc(fullname, strsize); - if (fullnameTmp) - { - fullname = fullnameTmp; - fullnameTmp = NULL; - memset(fullname + fullname_len, 0, strlen(tmp) + 4); - } else { - free(fullname); - fullname = NULL; - break; - } - } - - if (i > 0) strcat(fullname, " + "); - - strcat(fullname, tmp); - } - - return fullname; -} - -char *generateNSPDumpName(nspDumpType selectedNspDumpType, u32 titleIndex, bool useBrackets) -{ - if ((selectedNspDumpType == DUMP_APP_NSP && (!titleAppCount || !baseAppEntries || titleIndex >= titleAppCount)) || (selectedNspDumpType == DUMP_PATCH_NSP && (!titlePatchCount || !patchEntries || titleIndex >= titlePatchCount)) || (selectedNspDumpType == DUMP_ADDON_NSP && (!titleAddOnCount || !addOnEntries || titleIndex >= titleAddOnCount))) return NULL; - - u32 i; - size_t strsize = NAME_BUF_LEN; - - patch_addon_ctx_t *ptr = NULL; - - char *fullname = calloc(strsize + 1, sizeof(char)); - if (!fullname) return NULL; - - switch(selectedNspDumpType) - { - case DUMP_APP_NSP: - if (useBrackets) - { - snprintf(fullname, strsize, "%s [%016lX][v%u][BASE]", baseAppEntries[titleIndex].fixedName, baseAppEntries[titleIndex].titleId, baseAppEntries[titleIndex].version); - } else { - snprintf(fullname, strsize, "%s v%u (%016lX) (BASE)", baseAppEntries[titleIndex].fixedName, baseAppEntries[titleIndex].version, baseAppEntries[titleIndex].titleId); - } - break; - case DUMP_PATCH_NSP: - case DUMP_ADDON_NSP: - ptr = (selectedNspDumpType == DUMP_PATCH_NSP ? &(patchEntries[titleIndex]) : &(addOnEntries[titleIndex])); - - // Look for the parent base application name - if (titleAppCount && baseAppEntries) - { - for(i = 0; i < titleAppCount; i++) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(titleIndex, i, (selectedNspDumpType == DUMP_ADDON_NSP))) - { - if (useBrackets) - { - snprintf(fullname, strsize, "%s [%016lX][v%u][%s]", baseAppEntries[i].fixedName, ptr->titleId, ptr->version, (selectedNspDumpType == DUMP_PATCH_NSP ? "UPD" : "DLC")); - } else { - snprintf(fullname, strsize, "%s v%u (%016lX) (%s)", baseAppEntries[i].fixedName, ptr->version, ptr->titleId, (selectedNspDumpType == DUMP_PATCH_NSP ? "UPD" : "DLC")); - } - - break; - } - } - } - - if (!strlen(fullname)) - { - // Look for the parent base application name in orphan entries - if (orphanEntries && orphanEntriesCnt) - { - for(i = 0; i < orphanEntriesCnt; i++) - { - if (orphanEntries[i].index == titleIndex && strlen(orphanEntries[i].fixedName) && ((selectedNspDumpType == DUMP_PATCH_NSP && orphanEntries[i].type == ORPHAN_ENTRY_TYPE_PATCH) || (selectedNspDumpType == DUMP_ADDON_NSP && orphanEntries[i].type == ORPHAN_ENTRY_TYPE_ADDON))) - { - if (useBrackets) - { - snprintf(fullname, strsize, "%s [%016lX][v%u][%s]", orphanEntries[i].fixedName, ptr->titleId, ptr->version, (selectedNspDumpType == DUMP_PATCH_NSP ? "UPD" : "DLC")); - } else { - snprintf(fullname, strsize, "%s v%u (%016lX) (%s)", orphanEntries[i].fixedName, ptr->version, ptr->titleId, (selectedNspDumpType == DUMP_PATCH_NSP ? "UPD" : "DLC")); - } - - break; - } - } - } - - if (!strlen(fullname)) - { - // Nothing worked, just print the Title ID + version - if (useBrackets) - { - snprintf(fullname, strsize, "[%016lX][v%u][%s]", ptr->titleId, ptr->version, (selectedNspDumpType == DUMP_PATCH_NSP ? "UPD" : "DLC")); - } else { - snprintf(fullname, strsize, "%016lX v%u (%s)", ptr->titleId, ptr->version, (selectedNspDumpType == DUMP_PATCH_NSP ? "UPD" : "DLC")); - } - } - } - - break; - default: - free(fullname); - fullname = NULL; - break; - } - - return fullname; -} - -void retrieveDescriptionForPatchOrAddOn(u32 titleIndex, bool addOn, bool addAppName, const char *prefix, char *outBuf, size_t outBufSize) -{ - if ((!addOn && (!titlePatchCount || !patchEntries || titleIndex >= titlePatchCount)) || (addOn && (!titleAddOnCount || !addOnEntries || titleIndex >= titleAddOnCount)) || !outBuf || !outBufSize) return; - - u32 i; - bool addPrefix = (prefix && strlen(prefix)); - patch_addon_ctx_t *ptr = (!addOn ? &(patchEntries[titleIndex]) : &(addOnEntries[titleIndex])); - - // Check if we need to add the base application name - if (!addAppName || !titleAppCount || !baseAppEntries) - { - if (addPrefix) - { - snprintf(outBuf, outBufSize, "%s%016lX v%s", prefix, ptr->titleId, ptr->versionStr); - } else { - snprintf(outBuf, outBufSize, "%016lX v%s", ptr->titleId, ptr->versionStr); - } - - return; - } - - // Look for the parent base application name - for(i = 0; i < titleAppCount; i++) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(titleIndex, i, addOn)) - { - if (addPrefix) - { - snprintf(outBuf, outBufSize, "%s%s | %016lX v%s", prefix, baseAppEntries[i].name, ptr->titleId, ptr->versionStr); - } else { - snprintf(outBuf, outBufSize, "%s | %016lX v%s", baseAppEntries[i].name, ptr->titleId, ptr->versionStr); - } - - return; - } - } - - // Look for the parent base application name in orphan entries - if (orphanEntries != NULL && orphanEntriesCnt) - { - for(i = 0; i < orphanEntriesCnt; i++) - { - if (orphanEntries[i].index == titleIndex && strlen(orphanEntries[i].name) && ((!addOn && orphanEntries[i].type == ORPHAN_ENTRY_TYPE_PATCH) || (addOn && orphanEntries[i].type == ORPHAN_ENTRY_TYPE_ADDON))) - { - if (addPrefix) - { - snprintf(outBuf, outBufSize, "%s%s | %016lX v%s", prefix, orphanEntries[i].name, ptr->titleId, ptr->versionStr); - } else { - snprintf(outBuf, outBufSize, "%s | %016lX v%s", orphanEntries[i].name, ptr->titleId, ptr->versionStr); - } - - return; - } - } - } - - // Nothing worked, just print the Title ID + version - if (addPrefix) - { - snprintf(outBuf, outBufSize, "%s%016lX v%s", prefix, ptr->titleId, ptr->versionStr); - } else { - snprintf(outBuf, outBufSize, "%016lX v%s", ptr->titleId, ptr->versionStr); - } -} - -u32 calculateOrphanPatchOrAddOnCount(bool addOn) -{ - if ((!addOn && (!titlePatchCount || !patchEntries)) || (addOn && (!titleAddOnCount || !addOnEntries))) return 0; - - if ((!titleAppCount || !baseAppEntries) && ((!addOn && titlePatchCount && patchEntries) || (addOn && titleAddOnCount && addOnEntries))) return (!addOn ? titlePatchCount : titleAddOnCount); - - u32 i, j; - u32 titleCount = (!addOn ? titlePatchCount : titleAddOnCount); - u32 orphanCnt = 0; - - for(i = 0; i < titleCount; i++) - { - bool foundMatch = false; - - for(j = 0; j < titleAppCount; j++) - { - if ((!addOn && patchEntries[i].titleId == (baseAppEntries[j].titleId | APPLICATION_PATCH_BITMASK)) || (addOn && (addOnEntries[i].titleId & APPLICATION_ADDON_BITMASK) == (baseAppEntries[j].titleId & APPLICATION_ADDON_BITMASK))) - { - foundMatch = true; - break; - } - } - - if (foundMatch) continue; - - orphanCnt++; - } - - return orphanCnt; -} - -void generateOrphanPatchOrAddOnList() -{ - Result result; - u32 nsAppRecordCnt = 0; - - bool foundMatch; - u32 i, j, k; - - u32 orphanEntryIndex = 0; - u32 orphanPatchCount = calculateOrphanPatchOrAddOnCount(false); - u32 orphanAddOnCount = calculateOrphanPatchOrAddOnCount(true); - - if (!orphanPatchCount && !orphanAddOnCount) return; - - if (orphanEntries && orphanEntriesCnt && orphanEntriesCnt == (orphanPatchCount + orphanAddOnCount)) goto out; - - freeOrphanPatchOrAddOnList(); - - // Retrieve all cached Application IDs (assuming no one has more than 2048 cached base applications...) - NsApplicationRecord *appRecords = calloc(2048, sizeof(NsApplicationRecord)); - if (!appRecords) return; - - result = nsListApplicationRecord(appRecords, 2048, 0, (s32*)&nsAppRecordCnt); - if (R_FAILED(result)) - { - free(appRecords); - return; - } - - // Allocate memory for our orphan entries - orphanEntries = calloc(orphanPatchCount + orphanAddOnCount, sizeof(orphan_patch_addon_entry)); - if (!orphanEntries) - { - free(appRecords); - return; - } - - // Save orphan patch & add-on data - for(i = 0; i < 2; i++) - { - u32 titleCount = (i == 0 ? titlePatchCount : titleAddOnCount); - - for(j = 0; j < titleCount; j++) - { - foundMatch = false; - - if (titleAppCount && baseAppEntries) - { - for(k = 0; k < titleAppCount; k++) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(j, k, (i == 1))) - { - foundMatch = true; - break; - } - } - } - - if (foundMatch) continue; - - patch_addon_ctx_t *ptr = (i == 0 ? &(patchEntries[j]) : &(addOnEntries[j])); - - // Look for a matching Application ID in our NS records - for(k = 0; k < nsAppRecordCnt; k++) - { - if ((i == 0 && ptr->titleId == (appRecords[k].application_id | APPLICATION_PATCH_BITMASK)) || (i == 1 && (ptr->titleId & APPLICATION_ADDON_BITMASK) == (appRecords[k].application_id & APPLICATION_ADDON_BITMASK))) - { - if (getCachedBaseApplicationNacpMetadata(appRecords[k].application_id, orphanEntries[orphanEntryIndex].name, MAX_CHARACTERS(orphanEntries[orphanEntryIndex].name), NULL, 0, NULL)) - { - strtrim(orphanEntries[orphanEntryIndex].name); - snprintf(orphanEntries[orphanEntryIndex].fixedName, MAX_CHARACTERS(orphanEntries[orphanEntryIndex].fixedName), orphanEntries[orphanEntryIndex].name); - removeIllegalCharacters(orphanEntries[orphanEntryIndex].fixedName); - } - - break; - } - } - - if (strlen(orphanEntries[orphanEntryIndex].name)) - { - snprintf(orphanEntries[orphanEntryIndex].orphanListStr, MAX_CHARACTERS(orphanEntries[orphanEntryIndex].orphanListStr), "%s v%u (%016lX) (%s)", orphanEntries[orphanEntryIndex].name, ptr->version, ptr->titleId, (i == 0 ? "Update" : "DLC")); - } else { - snprintf(orphanEntries[orphanEntryIndex].orphanListStr, MAX_CHARACTERS(orphanEntries[orphanEntryIndex].orphanListStr), "%016lX v%u (%s)", ptr->titleId, ptr->version, (i == 0 ? "Update" : "DLC")); - } - - orphanEntries[orphanEntryIndex].index = j; - orphanEntries[orphanEntryIndex].type = (i == 0 ? ORPHAN_ENTRY_TYPE_PATCH : ORPHAN_ENTRY_TYPE_ADDON); - - orphanEntryIndex++; - } - } - - orphanEntriesCnt = (orphanPatchCount + orphanAddOnCount); - - free(appRecords); - - // Sort orphan titles by name - qsort(orphanEntries, orphanEntriesCnt, sizeof(orphan_patch_addon_entry), orphanEntryCmp); - -out: - if (!allocateFilenameBuffer(orphanEntriesCnt)) return; - - for(i = 0; i < orphanEntriesCnt; i++) - { - if (!addStringToFilenameBuffer(orphanEntries[i].orphanListStr)) return; - } -} - -bool checkIfBaseApplicationHasPatchOrAddOn(u32 appIndex, bool addOn) -{ - if (!titleAppCount || !baseAppEntries || appIndex >= titleAppCount || (!addOn && (!titlePatchCount || !patchEntries)) || (addOn && (!titleAddOnCount || !addOnEntries))) return false; - - u32 i; - u32 count = (!addOn ? titlePatchCount : titleAddOnCount); - - for(i = 0; i < count; i++) - { - if ((!addOn && (baseAppEntries[appIndex].titleId | APPLICATION_PATCH_BITMASK) == patchEntries[i].titleId) || (addOn && (baseAppEntries[appIndex].titleId & APPLICATION_ADDON_BITMASK) == (addOnEntries[i].titleId & APPLICATION_ADDON_BITMASK))) return true; - } - - return false; -} - -bool checkIfPatchOrAddOnBelongsToBaseApplication(u32 titleIndex, u32 appIndex, bool addOn) -{ - if (!titleAppCount || !baseAppEntries || appIndex >= titleAppCount || (!addOn && (!titlePatchCount || !patchEntries || titleIndex >= titlePatchCount)) || (addOn && (!titleAddOnCount || !addOnEntries || titleIndex >= titleAddOnCount))) return false; - - if ((!addOn && patchEntries[titleIndex].titleId == (baseAppEntries[appIndex].titleId | APPLICATION_PATCH_BITMASK)) || (addOn && (addOnEntries[titleIndex].titleId & APPLICATION_ADDON_BITMASK) == (baseAppEntries[appIndex].titleId & APPLICATION_ADDON_BITMASK))) return true; - - return false; -} - -u32 retrieveFirstPatchOrAddOnIndexFromBaseApplication(u32 appIndex, bool addOn) -{ - if (!titleAppCount || !baseAppEntries || appIndex >= titleAppCount || (!addOn && (!titlePatchCount || !patchEntries)) || (addOn && (!titleAddOnCount || !addOnEntries))) return 0; - - u32 titleIndex; - u32 count = (!addOn ? titlePatchCount : titleAddOnCount); - - for(titleIndex = 0; titleIndex < count; titleIndex++) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(titleIndex, appIndex, addOn)) return titleIndex; - } - - return 0; -} - -u32 retrievePreviousPatchOrAddOnIndexFromBaseApplication(u32 startTitleIndex, u32 appIndex, bool addOn) -{ - u32 count = (!addOn ? titlePatchCount : titleAddOnCount); - u32 retTitleIndex = startTitleIndex; - u32 curTitleIndex = 0; - - if (!startTitleIndex || startTitleIndex >= count || !titleAppCount || !baseAppEntries || appIndex >= titleAppCount || (!addOn && (!titlePatchCount || !patchEntries)) || (addOn && (!titleAddOnCount || !addOnEntries))) return retTitleIndex; - - for(curTitleIndex = startTitleIndex; curTitleIndex > 0; curTitleIndex--) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(curTitleIndex - 1, appIndex, addOn)) - { - retTitleIndex = (curTitleIndex - 1); - break; - } - } - - return retTitleIndex; -} - -u32 retrieveNextPatchOrAddOnIndexFromBaseApplication(u32 startTitleIndex, u32 appIndex, bool addOn) -{ - u32 count = (!addOn ? titlePatchCount : titleAddOnCount); - u32 retTitleIndex = startTitleIndex; - u32 curTitleIndex = 0; - - if (startTitleIndex >= count || !titleAppCount || !baseAppEntries || appIndex >= titleAppCount || (!addOn && (!titlePatchCount || !patchEntries)) || (addOn && (!titleAddOnCount || !addOnEntries))) return retTitleIndex; - - for(curTitleIndex = (startTitleIndex + 1); curTitleIndex < count; curTitleIndex++) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(curTitleIndex, appIndex, addOn)) - { - retTitleIndex = curTitleIndex; - break; - } - } - - return retTitleIndex; -} - -u32 retrieveLastPatchOrAddOnIndexFromBaseApplication(u32 appIndex, bool addOn) -{ - if (!titleAppCount || !baseAppEntries || appIndex >= titleAppCount || (!addOn && (!titlePatchCount || !patchEntries)) || (addOn && (!titleAddOnCount || !addOnEntries))) return 0; - - u32 titleIndex; - u32 count = (!addOn ? titlePatchCount : titleAddOnCount); - - for(titleIndex = count; titleIndex > 0; titleIndex--) - { - if (checkIfPatchOrAddOnBelongsToBaseApplication(titleIndex - 1, appIndex, addOn)) return (titleIndex - 1); - } - - return 0; -} - -void waitForButtonPress() -{ - uiDrawString(STRING_X_POS, STRING_Y_POS(breaks), FONT_COLOR_RGB, "Press any button to continue"); - - while(true) - { - uiUpdateStatusMsg(); - uiRefreshDisplay(); - - hidScanInput(); - - u64 keysDown = hidKeysAllDown(CONTROLLER_P1_AUTO); - - if (keysDown && !((keysDown & KEY_TOUCH) || (keysDown & KEY_LSTICK_LEFT) || (keysDown & KEY_LSTICK_RIGHT) || (keysDown & KEY_LSTICK_UP) || (keysDown & KEY_LSTICK_DOWN) || \ - (keysDown & KEY_RSTICK_LEFT) || (keysDown & KEY_RSTICK_RIGHT) || (keysDown & KEY_RSTICK_UP) || (keysDown & KEY_RSTICK_DOWN))) break; - } -} - void printProgressBar(progress_ctx_t *progressCtx, bool calcData, u64 chunkSize) { if (!progressCtx) return; @@ -3765,36 +1514,6 @@ bool cancelProcessCheck(progress_ctx_t *progressCtx) return false; } -void convertDataToHexString(const u8 *data, const u32 dataSize, char *outBuf, const u32 outBufSize) -{ - if (!data || !dataSize || !outBuf || !outBufSize || outBufSize < ((dataSize * 2) + 1)) return; - - u32 i; - char tmp[3] = {'\0'}; - - memset(outBuf, 0, outBufSize); - - for(i = 0; i < dataSize; i++) - { - sprintf(tmp, "%02x", data[i]); - strcat(outBuf, tmp); - } -} - -bool checkIfFileExists(const char *path) -{ - if (!path || !strlen(path)) return false; - - FILE *chkfile = fopen(path, "rb"); - if (chkfile) - { - fclose(chkfile); - return true; - } - - return false; -} - bool yesNoPrompt(const char *message) { if (message && strlen(message)) diff --git a/legacy/util.h b/legacy/util.h index b869c2e..66c50b7 100644 --- a/legacy/util.h +++ b/legacy/util.h @@ -118,67 +118,6 @@ #define CANCEL_BTN_SEC_HOLD 2 // The cancel button must be held for at least CANCEL_BTN_SEC_HOLD seconds to cancel an ongoing operation -typedef struct { - u8 signature[0x100]; - u32 magic; - u32 secureAreaStartAddr; - u32 backupAreaStartAddr; - u8 titleKeyIndex; - u8 size; - u8 headerVersion; - u8 flags; - u64 packageId; - u64 validDataEndAddr; - u8 iv[0x10]; - u64 rootHfs0HeaderOffset; - u64 rootHfs0HeaderSize; - u8 rootHfs0HeaderHash[SHA256_HASH_SIZE]; - u8 initialDataHash[SHA256_HASH_SIZE]; - u32 securityMode; - u32 t1KeyIndex; - u32 keyIndex; - u32 normalAreaEndAddr; - u8 encryptedInfoBlock[0x70]; -} PACKED gamecard_header_t; - -typedef struct { - u64 offset; - u64 size; - u8 *header; - u64 header_size; - u32 file_cnt; - u32 str_table_size; -} PACKED hfs0_partition_info; - -typedef enum { - ISTORAGE_PARTITION_NONE = 0, - ISTORAGE_PARTITION_NORMAL, - ISTORAGE_PARTITION_SECURE, - ISTORAGE_PARTITION_INVALID -} openIStoragePartition; - -typedef struct { - FsDeviceOperator fsOperatorInstance; - FsEventNotifier fsGameCardEventNotifier; - Event fsGameCardKernelEvent; - FsGameCardHandle fsGameCardHandle; - FsStorage fsGameCardStorage; - openIStoragePartition curIStorageIndex; - volatile bool isInserted; - gamecard_header_t header; - u8 *rootHfs0Header; - u32 hfs0PartitionCnt; - hfs0_partition_info *hfs0Partitions; - u64 size; - char sizeStr[32]; - u64 trimmedSize; - char trimmedSizeStr[32]; - u64 IStoragePartitionSizes[ISTORAGE_PARTITION_CNT]; - u64 updateTitleId; - u32 updateVersion; - char updateVersionStr[64]; -} gamecard_ctx_t; - typedef struct { u64 titleId; u32 version; @@ -211,22 +150,6 @@ typedef struct { char orphanListStr[NACP_APPNAME_LEN * 2]; } orphan_patch_addon_entry; -typedef struct { - u32 magic; - u32 file_cnt; - u32 str_table_size; - u32 reserved; -} PACKED hfs0_header; - -typedef struct { - u64 file_offset; - u64 file_size; - u32 filename_offset; - u32 hashed_region_size; - u64 reserved; - u8 hashed_region_sha256[0x20]; -} PACKED hfs0_file_entry; - typedef struct { int line_offset; u64 totalSize; @@ -323,69 +246,24 @@ typedef struct { void loadConfig(); void saveConfig(); -void closeGameCardStoragePartition(); -Result openGameCardStoragePartition(openIStoragePartition partitionIndex); -Result readGameCardStoragePartition(u64 off, void *buf, size_t len); - -void delay(u8 seconds); - -void convertSize(u64 size, char *out, size_t outSize); -void updateFreeSpace(); - void freeFilenameBuffer(void); -void initExeFsContext(); -void freeExeFsContext(); - -void initRomFsContext(); -void freeRomFsContext(); - -void initBktrContext(); -void freeBktrContext(); - void freeRomFsBrowserEntries(); void freeHfs0ExeFsEntriesSizes(); -u64 hidKeysAllDown(); -u64 hidKeysAllHeld(); - -void consoleErrorScreen(const char *fmt, ...); bool initApplicationResources(int argc, char **argv); void deinitApplicationResources(); -bool appletModeCheck(); void appletModeOperationWarning(); -void changeHomeButtonBlockStatus(bool block); void formatETAString(u64 curTime, char *out, size_t outSize); void generateSdCardEmmcTitleList(); -bool loadTitlesFromSdCardAndEmmc(NcmContentMetaType metaType); -void freeTitlesFromSdCardAndEmmc(NcmContentMetaType metaType); - -void removeIllegalCharacters(char *name); - -void strtrim(char *str); - -void loadTitleInfo(); - void truncateBrowserEntryName(char *str); bool getHfs0FileList(u32 partition); -bool readFileFromSecureHfs0PartitionByName(const char *filename, u64 offset, void *outBuf, size_t bufSize); - -bool calculateExeFsExtractedDataSize(u64 *out); - -bool calculateRomFsFullExtractedSize(bool usePatch, u64 *out); - -bool calculateRomFsExtractedDirSize(u32 dir_offset, bool usePatch, u64 *out); - -bool retrieveContentInfosFromTitle(NcmStorageId storageId, NcmContentMetaType metaType, u32 titleCount, u32 titleIndex, NcmContentInfo **outContentInfos, u32 *outContentInfoCnt); - -void removeConsoleDataFromTicket(title_rights_ctx *rights_info); - bool readNcaExeFsSection(u32 titleIndex, bool usePatch); int readNcaRomFsSection(u32 titleIndex, selectedRomFsType curRomFsType, int desiredIdOffset); @@ -394,40 +272,12 @@ bool getExeFsFileList(); bool getRomFsFileList(u32 dir_offset, bool usePatch); -char *generateGameCardDumpName(bool useBrackets); - -char *generateNSPDumpName(nspDumpType selectedNspDumpType, u32 titleIndex, bool useBrackets); - -void retrieveDescriptionForPatchOrAddOn(u32 titleIndex, bool addOn, bool addAppName, const char *prefix, char *outBuf, size_t outBufSize); - -u32 calculateOrphanPatchOrAddOnCount(bool addOn); - -void generateOrphanPatchOrAddOnList(); - -bool checkIfBaseApplicationHasPatchOrAddOn(u32 appIndex, bool addOn); - -bool checkIfPatchOrAddOnBelongsToBaseApplication(u32 titleIndex, u32 appIndex, bool addOn); - -u32 retrieveFirstPatchOrAddOnIndexFromBaseApplication(u32 appIndex, bool addOn); - -u32 retrievePreviousPatchOrAddOnIndexFromBaseApplication(u32 startTitleIndex, u32 appIndex, bool addOn); - -u32 retrieveNextPatchOrAddOnIndexFromBaseApplication(u32 startTitleIndex, u32 appIndex, bool addOn); - -u32 retrieveLastPatchOrAddOnIndexFromBaseApplication(u32 appIndex, bool addOn); - -void waitForButtonPress(); - void printProgressBar(progress_ctx_t *progressCtx, bool calcData, u64 chunkSize); void setProgressBarError(progress_ctx_t *progressCtx); bool cancelProcessCheck(progress_ctx_t *progressCtx); -void convertDataToHexString(const u8 *data, const u32 dataSize, char *outBuf, const u32 outBufSize); - -bool checkIfFileExists(const char *path); - bool yesNoPrompt(const char *message); bool checkIfDumpedXciContainsCertificate(const char *xciPath);