mirror of
https://github.com/DarkMatterCore/nxdumptool.git
synced 2025-01-26 19:23:16 -03:00
3023 lines
135 KiB
C
3023 lines
135 KiB
C
#include <stdarg.h>
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <math.h>
|
|
|
|
#include <switch.h>
|
|
|
|
#include <ft2build.h>
|
|
#include FT_FREETYPE_H
|
|
|
|
#include <turbojpeg.h>
|
|
|
|
#include "dumper.h"
|
|
#include "fs_ext.h"
|
|
#include "ui.h"
|
|
#include "util.h"
|
|
#include "keys.h"
|
|
|
|
/* Extern variables */
|
|
|
|
extern AppletType programAppletType;
|
|
|
|
extern bool gameCardInserted;
|
|
|
|
extern char gameCardSizeStr[32], trimmedCardSizeStr[32];
|
|
|
|
extern u8 *hfs0_header;
|
|
extern u64 hfs0_offset, hfs0_size;
|
|
extern u32 hfs0_partition_cnt;
|
|
|
|
extern u8 *partitionHfs0Header;
|
|
extern u64 partitionHfs0HeaderOffset, partitionHfs0HeaderSize;
|
|
extern u32 partitionHfs0FileCount, partitionHfs0StrTableSize;
|
|
|
|
extern u32 titleAppCount;
|
|
extern u64 *titleAppTitleID;
|
|
extern u32 *titleAppVersion;
|
|
extern FsStorageId *titleAppStorageId;
|
|
|
|
extern u32 titlePatchCount;
|
|
extern u64 *titlePatchTitleID;
|
|
extern u32 *titlePatchVersion;
|
|
extern FsStorageId *titleAppStorageId;
|
|
|
|
extern u32 titleAddOnCount;
|
|
extern u64 *titleAddOnTitleID;
|
|
extern u32 *titleAddOnVersion;
|
|
extern FsStorageId *titleAppStorageId;
|
|
|
|
extern char **titleName;
|
|
extern char **titleAuthor;
|
|
extern char **titleAppVersionStr;
|
|
extern u8 **titleIcon;
|
|
|
|
extern char gameCardUpdateVersionStr[128];
|
|
|
|
extern char *filenameBuffer;
|
|
extern char *filenames[FILENAME_MAX_CNT];
|
|
extern int filenamesCount;
|
|
|
|
extern char curRomFsPath[NAME_BUF_LEN];
|
|
extern romfs_browser_entry *romFsBrowserEntries;
|
|
|
|
extern orphan_patch_addon_entry *orphanEntries;
|
|
|
|
extern char strbuf[NAME_BUF_LEN * 4];
|
|
|
|
/* Statically allocated variables */
|
|
|
|
static PlFontData standardFont;
|
|
static PlFontData nintendoExtFont;
|
|
static FT_Library library;
|
|
static FT_Face standardFontFace;
|
|
static FT_Face nintendoExtFontFace;
|
|
static Framebuffer fb;
|
|
|
|
static u32 *framebuf = NULL;
|
|
static u32 framebuf_width = 0;
|
|
|
|
int cursor = 0;
|
|
int scroll = 0;
|
|
int breaks = 0;
|
|
int font_height = 0;
|
|
|
|
curMenuType menuType;
|
|
static bool orphanMode = false;
|
|
|
|
static u32 selectedAppInfoIndex = 0;
|
|
static u32 selectedAppIndex;
|
|
static u32 selectedPatchIndex;
|
|
static u32 selectedAddOnIndex;
|
|
static u32 selectedPartitionIndex;
|
|
static u32 selectedFileIndex;
|
|
|
|
static nspDumpType selectedNspDumpType;
|
|
|
|
static bool highlight = false;
|
|
|
|
static bool isFat32 = false, dumpCert = false, trimDump = false, calcCrc = true, setXciArchiveBit = false, removeConsoleData = false, tiklessDump = false;
|
|
|
|
static char statusMessage[2048] = {'\0'};
|
|
static int statusMessageFadeout = 0;
|
|
|
|
u64 freeSpace = 0;
|
|
static char freeSpaceStr[64] = {'\0'};
|
|
|
|
static UIState uiState;
|
|
|
|
static const char *dirNormalIconPath = "romfs:/browser/dir_normal.jpg";
|
|
static u8 *dirNormalIconBuf = NULL;
|
|
|
|
static const char *dirHighlightIconPath = "romfs:/browser/dir_highlight.jpg";
|
|
static u8 *dirHighlightIconBuf = NULL;
|
|
|
|
static const char *fileNormalIconPath = "romfs:/browser/file_normal.jpg";
|
|
static u8 *fileNormalIconBuf = NULL;
|
|
|
|
static const char *fileHighlightIconPath = "romfs:/browser/file_highlight.jpg";
|
|
static u8 *fileHighlightIconBuf = NULL;
|
|
|
|
static const char *appHeadline = "NXDumpTool v" APP_VERSION ".\nOriginal codebase by MCMrARM.\nUpdated and maintained by DarkMatterCore.\n\n";
|
|
static const char *appControlsCommon = "[ " NINTENDO_FONT_DPAD " / " NINTENDO_FONT_LSTICK " / " NINTENDO_FONT_RSTICK " ] Move | [ " NINTENDO_FONT_A " ] Select | [ " NINTENDO_FONT_B " ] Back | [ " NINTENDO_FONT_PLUS " ] Exit";
|
|
static const char *appControlsGameCardMultiApp = "[ " NINTENDO_FONT_DPAD " / " NINTENDO_FONT_LSTICK " / " NINTENDO_FONT_RSTICK " ] Move | [ " NINTENDO_FONT_A " ] Select | [ " NINTENDO_FONT_B " ] Back | [ " NINTENDO_FONT_L " / " NINTENDO_FONT_R " / " NINTENDO_FONT_ZL " / " NINTENDO_FONT_ZR " ] Change displayed base application info | [ " NINTENDO_FONT_PLUS " ] Exit";
|
|
static const char *appControlsNoContent = "[ " NINTENDO_FONT_B " ] Back | [ " NINTENDO_FONT_PLUS " ] Exit";
|
|
static const char *appControlsSdCardEmmcFull = "[ " NINTENDO_FONT_DPAD " / " NINTENDO_FONT_LSTICK " / " NINTENDO_FONT_RSTICK " ] Move | [ " NINTENDO_FONT_A " ] Select | [ " NINTENDO_FONT_B " ] Back | [ " NINTENDO_FONT_Y " ] Dump installed content with missing base application | [ " NINTENDO_FONT_PLUS " ] Exit";
|
|
static const char *appControlsSdCardEmmcNoApp = "[ " NINTENDO_FONT_B " ] Back | [ " NINTENDO_FONT_Y " ] Dump installed content with missing base application | [ " NINTENDO_FONT_PLUS " ] Exit";
|
|
|
|
static const char *mainMenuItems[] = { "Dump gamecard content", "Dump SD card / eMMC (NANDUSER) content", "Update options" };
|
|
static const char *gameCardMenuItems[] = { "Cartridge Image (XCI) dump", "Nintendo Submission Package (NSP) dump", "HFS0 options", "ExeFS options", "RomFS options", "Dump gamecard certificate" };
|
|
static const char *xciDumpMenuItems[] = { "Start XCI dump process", "Split output dump (FAT32 support): ", "Create directory with archive bit set: ", "Dump certificate: ", "Trim output dump: ", "CRC32 checksum calculation + dump verification: " };
|
|
static const char *nspDumpGameCardMenuItems[] = { "Dump base application NSP", "Dump bundled update NSP", "Dump bundled DLC NSP" };
|
|
static const char *nspDumpSdCardEmmcMenuItems[] = { "Dump base application NSP", "Dump installed update NSP", "Dump installed DLC NSP" };
|
|
static const char *nspAppDumpMenuItems[] = { "Start NSP dump process", "Split output dump (FAT32 support): ", "CRC32 checksum calculation: ", "Remove console specific data: ", "Generate ticket-less dump: ", "Base application to dump: " };
|
|
static const char *nspPatchDumpMenuItems[] = { "Start NSP dump process", "Split output dump (FAT32 support): ", "CRC32 checksum calculation: ", "Remove console specific data: ", "Generate ticket-less dump: ", "Update to dump: " };
|
|
static const char *nspAddOnDumpMenuItems[] = { "Start NSP dump process", "Split output dump (FAT32 support): ", "CRC32 checksum calculation: ", "Remove console specific data: ", "Generate ticket-less dump: ", "DLC to dump: " };
|
|
static const char *hfs0MenuItems[] = { "Raw HFS0 partition dump", "HFS0 partition data dump", "Browse HFS0 partitions" };
|
|
static const char *hfs0PartitionDumpType1MenuItems[] = { "Dump HFS0 partition 0 (Update)", "Dump HFS0 partition 1 (Normal)", "Dump HFS0 partition 2 (Secure)" };
|
|
static const char *hfs0PartitionDumpType2MenuItems[] = { "Dump HFS0 partition 0 (Update)", "Dump HFS0 partition 1 (Logo)", "Dump HFS0 partition 2 (Normal)", "Dump HFS0 partition 3 (Secure)" };
|
|
static const char *hfs0BrowserType1MenuItems[] = { "Browse HFS0 partition 0 (Update)", "Browse HFS0 partition 1 (Normal)", "Browse HFS0 partition 2 (Secure)" };
|
|
static const char *hfs0BrowserType2MenuItems[] = { "Browse HFS0 partition 0 (Update)", "Browse HFS0 partition 1 (Logo)", "Browse HFS0 partition 2 (Normal)", "Browse HFS0 partition 3 (Secure)" };
|
|
static const char *exeFsMenuItems[] = { "ExeFS section data dump", "Browse ExeFS section" };
|
|
static const char *exeFsSectionDumpMenuItems[] = { "Start ExeFS data dump process", "Bundled application to dump: " };
|
|
static const char *exeFsSectionBrowserMenuItems[] = { "Browse ExeFS section", "Bundled application to browse: " };
|
|
static const char *romFsMenuItems[] = { "RomFS section data dump", "Browse RomFS section" };
|
|
static const char *romFsSectionDumpMenuItems[] = { "Start RomFS data dump process", "Bundled application to dump: " };
|
|
static const char *romFsSectionBrowserMenuItems[] = { "Browse RomFS section", "Bundled application to browse: " };
|
|
static const char *sdCardEmmcMenuItems[] = { "Nintendo Submission Package (NSP) dump", "ExeFS options", "RomFS options" };
|
|
static const char *updateMenuItems[] = { "Update NSWDB.COM XML database", "Update application" };
|
|
|
|
void uiFill(int x, int y, int width, int height, u8 r, u8 g, u8 b)
|
|
{
|
|
/* Perform validity checks */
|
|
if ((x + width) < 0 || (y + height) < 0 || x >= FB_WIDTH || y >= FB_HEIGHT) return;
|
|
|
|
if (x < 0)
|
|
{
|
|
width += x;
|
|
x = 0;
|
|
}
|
|
|
|
if (y < 0)
|
|
{
|
|
height += y;
|
|
y = 0;
|
|
}
|
|
|
|
if ((x + width) >= FB_WIDTH) width = (FB_WIDTH - x);
|
|
|
|
if ((y + height) >= FB_HEIGHT) height = (FB_HEIGHT - y);
|
|
|
|
if (framebuf == NULL)
|
|
{
|
|
/* Begin new frame */
|
|
u32 stride;
|
|
framebuf = (u32*)framebufferBegin(&fb, &stride);
|
|
framebuf_width = (stride / sizeof(u32));
|
|
}
|
|
|
|
u32 lx, ly;
|
|
u32 framex, framey;
|
|
|
|
for (ly = 0; ly < height; ly++)
|
|
{
|
|
for (lx = 0; lx < width; lx++)
|
|
{
|
|
framex = (x + lx);
|
|
framey = (y + ly);
|
|
|
|
framebuf[(framey * framebuf_width) + framex] = RGBA8_MAXALPHA(r, g, b);
|
|
}
|
|
}
|
|
}
|
|
|
|
void uiDrawIcon(const u8 *icon, int width, int height, int x, int y)
|
|
{
|
|
/* Perform validity checks */
|
|
if (!icon || !width || !height || (x + width) < 0 || (y + height) < 0 || x >= FB_WIDTH || y >= FB_HEIGHT) return;
|
|
|
|
if (x < 0)
|
|
{
|
|
width += x;
|
|
x = 0;
|
|
}
|
|
|
|
if (y < 0)
|
|
{
|
|
height += y;
|
|
y = 0;
|
|
}
|
|
|
|
if ((x + width) >= FB_WIDTH) width = (FB_WIDTH - x);
|
|
|
|
if ((y + height) >= FB_HEIGHT) height = (FB_HEIGHT - y);
|
|
|
|
if (framebuf == NULL)
|
|
{
|
|
/* Begin new frame */
|
|
u32 stride;
|
|
framebuf = (u32*)framebufferBegin(&fb, &stride);
|
|
framebuf_width = (stride / sizeof(u32));
|
|
}
|
|
|
|
u32 lx, ly;
|
|
u32 framex, framey;
|
|
u32 pos = 0;
|
|
|
|
for (ly = 0; ly < height; ly++)
|
|
{
|
|
for (lx = 0; lx < width; lx++)
|
|
{
|
|
framex = (x + lx);
|
|
framey = (y + ly);
|
|
|
|
pos = (((ly * width) + lx) * 3);
|
|
|
|
framebuf[(framey * framebuf_width) + framex] = RGBA8_MAXALPHA(icon[pos], icon[pos + 1], icon[pos + 2]);
|
|
}
|
|
}
|
|
}
|
|
|
|
bool uiLoadJpgFromMem(u8 *rawJpg, size_t rawJpgSize, int expectedWidth, int expectedHeight, int desiredWidth, int desiredHeight, u8 **outBuf)
|
|
{
|
|
if (!rawJpg || !rawJpgSize || !expectedWidth || !expectedHeight || !desiredWidth || !desiredHeight || !outBuf)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: invalid parameters to process JPG image buffer.");
|
|
return false;
|
|
}
|
|
|
|
int ret, w, h, samp;
|
|
tjhandle _jpegDecompressor = NULL;
|
|
bool success = false;
|
|
|
|
bool foundScalingFactor = false;
|
|
int i, numScalingFactors = 0, pitch;
|
|
tjscalingfactor *scalingFactors = NULL;
|
|
|
|
u8 *jpgScaledBuf = NULL;
|
|
|
|
_jpegDecompressor = tjInitDecompress();
|
|
if (_jpegDecompressor)
|
|
{
|
|
ret = tjDecompressHeader2(_jpegDecompressor, rawJpg, rawJpgSize, &w, &h, &samp);
|
|
if (ret != -1)
|
|
{
|
|
if (w == expectedWidth && h == expectedHeight)
|
|
{
|
|
scalingFactors = tjGetScalingFactors(&numScalingFactors);
|
|
if (scalingFactors)
|
|
{
|
|
for(i = 0; i < numScalingFactors; i++)
|
|
{
|
|
if (TJSCALED(expectedWidth, scalingFactors[i]) == desiredWidth && TJSCALED(expectedHeight, scalingFactors[i]) == desiredHeight)
|
|
{
|
|
foundScalingFactor = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (foundScalingFactor)
|
|
{
|
|
pitch = TJPAD(desiredWidth * tjPixelSize[TJPF_RGB]);
|
|
|
|
jpgScaledBuf = malloc(pitch * desiredHeight);
|
|
if (jpgScaledBuf)
|
|
{
|
|
ret = tjDecompress2(_jpegDecompressor, rawJpg, rawJpgSize, jpgScaledBuf, desiredWidth, 0, desiredHeight, TJPF_RGB, TJFLAG_ACCURATEDCT);
|
|
if (ret != -1)
|
|
{
|
|
*outBuf = jpgScaledBuf;
|
|
success = true;
|
|
} else {
|
|
free(jpgScaledBuf);
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: tjDecompress2 failed (%d).", ret);
|
|
}
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: unable to allocated memory for the scaled RGB image output.");
|
|
}
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: unable to find a valid scaling factor.");
|
|
}
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: error retrieving scaling factors.");
|
|
}
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: invalid image width/height.");
|
|
}
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: tjDecompressHeader2 failed (%d).", ret);
|
|
}
|
|
|
|
tjDestroy(_jpegDecompressor);
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromMem: tjInitDecompress failed.");
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
bool uiLoadJpgFromFile(const char *filename, int expectedWidth, int expectedHeight, int desiredWidth, int desiredHeight, u8 **outBuf)
|
|
{
|
|
if (!filename || !desiredWidth || !desiredHeight || !outBuf)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromFile: invalid parameters to process JPG image file.\n");
|
|
return false;
|
|
}
|
|
|
|
u8 *buf = NULL;
|
|
FILE *fp = NULL;
|
|
size_t filesize = 0, read = 0;
|
|
|
|
fp = fopen(filename, "rb");
|
|
if (!fp)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromFile: failed to open file \"%s\".\n", filename);
|
|
return false;
|
|
}
|
|
|
|
fseek(fp, 0, SEEK_END);
|
|
filesize = ftell(fp);
|
|
rewind(fp);
|
|
|
|
if (!filesize)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromFile: file \"%s\" is empty.\n", filename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
|
|
buf = malloc(filesize);
|
|
if (!buf)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromFile: error allocating memory for image \"%s\".\n", filename);
|
|
fclose(fp);
|
|
return false;
|
|
}
|
|
|
|
read = fread(buf, 1, filesize, fp);
|
|
|
|
fclose(fp);
|
|
|
|
if (read != filesize)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "uiLoadJpgFromFile: error reading image \"%s\".\n", filename);
|
|
free(buf);
|
|
return false;
|
|
}
|
|
|
|
bool ret = uiLoadJpgFromMem(buf, filesize, expectedWidth, expectedHeight, desiredWidth, desiredHeight, outBuf);
|
|
|
|
free(buf);
|
|
|
|
if (!ret) strcat(strbuf, "\n");
|
|
|
|
return ret;
|
|
}
|
|
|
|
void uiDrawChar(FT_Bitmap *bitmap, int x, int y, u8 r, u8 g, u8 b)
|
|
{
|
|
if (framebuf == NULL) return;
|
|
|
|
u32 framex, framey;
|
|
u32 tmpx, tmpy;
|
|
u8 *imageptr = bitmap->buffer;
|
|
|
|
u8 src_val;
|
|
float opacity;
|
|
|
|
u8 fontR;
|
|
u8 fontG;
|
|
u8 fontB;
|
|
|
|
if (bitmap->pixel_mode != FT_PIXEL_MODE_GRAY) return;
|
|
|
|
for(tmpy = 0; tmpy < bitmap->rows; tmpy++)
|
|
{
|
|
for (tmpx = 0; tmpx < bitmap->width; tmpx++)
|
|
{
|
|
framex = (x + tmpx);
|
|
framey = (y + tmpy);
|
|
|
|
if (framex >= FB_WIDTH || framey >= FB_HEIGHT) continue;
|
|
|
|
src_val = imageptr[tmpx];
|
|
if (!src_val)
|
|
{
|
|
/* Render background color */
|
|
if (highlight)
|
|
{
|
|
framebuf[(framey * framebuf_width) + framex] = RGBA8_MAXALPHA(HIGHLIGHT_BG_COLOR_R, HIGHLIGHT_BG_COLOR_G, HIGHLIGHT_BG_COLOR_B);
|
|
} else {
|
|
framebuf[(framey * framebuf_width) + framex] = RGBA8_MAXALPHA(BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
|
|
}
|
|
} else {
|
|
/* Calculate alpha (opacity) */
|
|
opacity = (src_val / 255.0);
|
|
|
|
if (highlight)
|
|
{
|
|
fontR = (r * opacity + (1 - opacity) * HIGHLIGHT_BG_COLOR_R);
|
|
fontG = (g * opacity + (1 - opacity) * HIGHLIGHT_BG_COLOR_G);
|
|
fontB = (b * opacity + (1 - opacity) * HIGHLIGHT_BG_COLOR_B);
|
|
} else {
|
|
fontR = (r * opacity + (1 - opacity) * BG_COLOR_RGB);
|
|
fontG = (g * opacity + (1 - opacity) * BG_COLOR_RGB);
|
|
fontB = (b * opacity + (1 - opacity) * BG_COLOR_RGB);
|
|
}
|
|
|
|
framebuf[(framey * framebuf_width) + framex] = RGBA8_MAXALPHA(fontR, fontG, fontB);
|
|
}
|
|
}
|
|
|
|
imageptr += bitmap->pitch;
|
|
}
|
|
}
|
|
|
|
void uiScroll()
|
|
{
|
|
if (framebuf == NULL)
|
|
{
|
|
/* Begin new frame */
|
|
u32 stride;
|
|
framebuf = (u32*)framebufferBegin(&fb, &stride);
|
|
framebuf_width = (stride / sizeof(u32));
|
|
}
|
|
|
|
u32 lx, ly;
|
|
|
|
for (ly = 0; ly < (FB_HEIGHT - font_height - 8); ly++)
|
|
{
|
|
for (lx = 0; lx < FB_WIDTH; lx++)
|
|
{
|
|
framebuf[(ly * framebuf_width) + lx] = framebuf[((ly + font_height) * framebuf_width) + lx];
|
|
}
|
|
}
|
|
|
|
uiFill(0, FB_HEIGHT - (8 + (font_height + (font_height / 4))), FB_WIDTH, (8 + (font_height + (font_height / 4))), BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
|
|
|
|
breaks = (FB_HEIGHT - (8 + (font_height + (font_height / 4))) + (font_height / 8));
|
|
}
|
|
|
|
void uiDrawString(const char *string, int x, int y, u8 r, u8 g, u8 b)
|
|
{
|
|
u32 tmpx = (x <= 8 ? 8 : (x + 8));
|
|
u32 tmpy = (font_height + (y <= 8 ? 8 : (y + 8)));
|
|
FT_Error ret = 0;
|
|
FT_UInt glyph_index;
|
|
FT_GlyphSlot standardFontSlot = standardFontFace->glyph;
|
|
FT_GlyphSlot nintendoExtFontSlot = nintendoExtFontFace->glyph;
|
|
|
|
u32 i;
|
|
u32 str_size = strlen(string);
|
|
u32 tmpchar;
|
|
ssize_t unitcount = 0;
|
|
|
|
if (framebuf == NULL)
|
|
{
|
|
/* Begin new frame */
|
|
u32 stride;
|
|
framebuf = (u32*)framebufferBegin(&fb, &stride);
|
|
framebuf_width = (stride / sizeof(u32));
|
|
}
|
|
|
|
if (tmpy >= FB_HEIGHT)
|
|
{
|
|
tmpy = (FB_HEIGHT - (8 + (font_height + (font_height / 4))) + (font_height / 8));
|
|
uiScroll();
|
|
}
|
|
|
|
for(i = 0; i < str_size;)
|
|
{
|
|
bool useNintendoExt = (string[i] == 0xE0);
|
|
|
|
if (useNintendoExt)
|
|
{
|
|
tmpchar = (((string[i] << 8) & 0xFF00) | string[i + 1]);
|
|
i += 2;
|
|
} else {
|
|
unitcount = decode_utf8(&tmpchar, (const u8*)&string[i]);
|
|
if (unitcount <= 0) break;
|
|
i += unitcount;
|
|
|
|
if (tmpchar == '\n')
|
|
{
|
|
tmpx = 8;
|
|
tmpy += ((font_height + (font_height / 4)) + (font_height / 8));
|
|
breaks++;
|
|
continue;
|
|
} else
|
|
if (tmpchar == '\t')
|
|
{
|
|
tmpx += (font_height * TAB_WIDTH);
|
|
continue;
|
|
} else
|
|
if (tmpchar == '\r')
|
|
{
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (useNintendoExt)
|
|
{
|
|
glyph_index = FT_Get_Char_Index(nintendoExtFontFace, tmpchar);
|
|
|
|
ret = FT_Load_Glyph(nintendoExtFontFace, glyph_index, FT_LOAD_DEFAULT);
|
|
if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL);
|
|
|
|
if (ret) break;
|
|
|
|
if ((tmpx + (nintendoExtFontSlot->advance.x >> 6)) >= (FB_WIDTH - 8))
|
|
{
|
|
tmpx = 8;
|
|
tmpy += ((font_height + (font_height / 4)) + (font_height / 8));
|
|
breaks++;
|
|
}
|
|
|
|
uiDrawChar(&nintendoExtFontSlot->bitmap, tmpx + nintendoExtFontSlot->bitmap_left, tmpy - nintendoExtFontSlot->bitmap_top, r, g, b);
|
|
|
|
tmpx += (nintendoExtFontSlot->advance.x >> 6);
|
|
tmpy += (nintendoExtFontSlot->advance.y >> 6);
|
|
} else {
|
|
glyph_index = FT_Get_Char_Index(standardFontFace, tmpchar);
|
|
|
|
ret = FT_Load_Glyph(standardFontFace, glyph_index, FT_LOAD_DEFAULT);
|
|
if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL);
|
|
|
|
if (ret) break;
|
|
|
|
if ((tmpx + (standardFontSlot->advance.x >> 6)) >= (FB_WIDTH - 8))
|
|
{
|
|
tmpx = 8;
|
|
tmpy += ((font_height + (font_height / 4)) + (font_height / 8));
|
|
breaks++;
|
|
}
|
|
|
|
uiDrawChar(&standardFontSlot->bitmap, tmpx + standardFontSlot->bitmap_left, tmpy - standardFontSlot->bitmap_top, r, g, b);
|
|
|
|
tmpx += (standardFontSlot->advance.x >> 6);
|
|
tmpy += (standardFontSlot->advance.y >> 6);
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 uiGetStrWidth(char *string)
|
|
{
|
|
if (!string || !strlen(string)) return 0;
|
|
|
|
FT_Error ret = 0;
|
|
FT_UInt glyph_index;
|
|
FT_GlyphSlot standardFontSlot = standardFontFace->glyph;
|
|
FT_GlyphSlot nintendoExtFontSlot = nintendoExtFontFace->glyph;
|
|
|
|
u32 i;
|
|
u32 str_size = strlen(string);
|
|
u32 tmpchar;
|
|
ssize_t unitcount = 0;
|
|
u32 width = 0;
|
|
|
|
for(i = 0; i < str_size;)
|
|
{
|
|
bool useNintendoExt = (string[i] == 0xE0);
|
|
|
|
if (useNintendoExt)
|
|
{
|
|
tmpchar = (((string[i] << 8) & 0xFF00) | string[i + 1]);
|
|
i += 2;
|
|
} else {
|
|
unitcount = decode_utf8(&tmpchar, (const u8*)&string[i]);
|
|
if (unitcount <= 0) break;
|
|
i += unitcount;
|
|
|
|
if (tmpchar == '\n' || tmpchar == '\r')
|
|
{
|
|
continue;
|
|
} else
|
|
if (tmpchar == '\t')
|
|
{
|
|
width += (font_height * TAB_WIDTH);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (useNintendoExt)
|
|
{
|
|
glyph_index = FT_Get_Char_Index(nintendoExtFontFace, tmpchar);
|
|
|
|
ret = FT_Load_Glyph(nintendoExtFontFace, glyph_index, FT_LOAD_DEFAULT);
|
|
if (ret == 0) ret = FT_Render_Glyph(nintendoExtFontFace->glyph, FT_RENDER_MODE_NORMAL);
|
|
|
|
if (ret) break;
|
|
|
|
width += (nintendoExtFontSlot->advance.x >> 6);
|
|
} else {
|
|
glyph_index = FT_Get_Char_Index(standardFontFace, tmpchar);
|
|
|
|
ret = FT_Load_Glyph(standardFontFace, glyph_index, FT_LOAD_DEFAULT);
|
|
if (ret == 0) ret = FT_Render_Glyph(standardFontFace->glyph, FT_RENDER_MODE_NORMAL);
|
|
|
|
if (ret) break;
|
|
|
|
width += (standardFontSlot->advance.x >> 6);
|
|
}
|
|
}
|
|
|
|
return width;
|
|
}
|
|
|
|
void uiRefreshDisplay()
|
|
{
|
|
if (framebuf != NULL)
|
|
{
|
|
framebufferEnd(&fb);
|
|
framebuf = NULL;
|
|
framebuf_width = 0;
|
|
}
|
|
}
|
|
|
|
void uiStatusMsg(const char *fmt, ...)
|
|
{
|
|
statusMessageFadeout = 1000;
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
vsnprintf(statusMessage, sizeof(statusMessage) / sizeof(statusMessage[0]), fmt, args);
|
|
va_end(args);
|
|
}
|
|
|
|
void uiUpdateStatusMsg()
|
|
{
|
|
if (!strlen(statusMessage) || !statusMessageFadeout) return;
|
|
|
|
if ((statusMessageFadeout - 4) > BG_COLOR_RGB)
|
|
{
|
|
int fadeout = (statusMessageFadeout > 255 ? 255 : statusMessageFadeout);
|
|
uiFill(0, FB_HEIGHT - (8 + (font_height + (font_height / 4))), FB_WIDTH, (8 + (font_height + (font_height / 4))), BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
|
|
uiDrawString(statusMessage, 8, (FB_HEIGHT - (16 + (font_height + (font_height / 4))) + (font_height / 8)), fadeout, fadeout, fadeout);
|
|
statusMessageFadeout -= 4;
|
|
} else {
|
|
statusMessageFadeout = 0;
|
|
}
|
|
}
|
|
|
|
void uiPleaseWait(u8 wait)
|
|
{
|
|
uiDrawString("Please wait...", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
uiRefreshDisplay();
|
|
if (wait) delay(wait);
|
|
}
|
|
|
|
void uiUpdateFreeSpace()
|
|
{
|
|
getSdCardFreeSpace(&freeSpace);
|
|
|
|
char tmp[32] = {'\0'};
|
|
convertSize(freeSpace, tmp, sizeof(tmp) / sizeof(tmp[0]));
|
|
|
|
snprintf(freeSpaceStr, sizeof(freeSpaceStr) / sizeof(freeSpaceStr[0]), "Free SD card space: %s.", tmp);
|
|
}
|
|
|
|
void uiClearScreen()
|
|
{
|
|
uiFill(0, 0, FB_WIDTH, FB_HEIGHT, BG_COLOR_RGB, BG_COLOR_RGB, BG_COLOR_RGB);
|
|
}
|
|
|
|
void uiPrintHeadline()
|
|
{
|
|
breaks = 0;
|
|
uiClearScreen();
|
|
uiDrawString(appHeadline, 8, 8, 255, 255, 255);
|
|
}
|
|
|
|
void error_screen(const char *fmt, ...)
|
|
{
|
|
consoleInit(NULL);
|
|
|
|
va_list va;
|
|
va_start(va, fmt);
|
|
vprintf(fmt, va);
|
|
va_end(va);
|
|
|
|
printf("Press any button to exit.\n");
|
|
|
|
while(appletMainLoop())
|
|
{
|
|
hidScanInput();
|
|
|
|
u32 keysDown = hidKeysDown(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;
|
|
|
|
consoleUpdate(NULL);
|
|
}
|
|
|
|
consoleExit(NULL);
|
|
}
|
|
|
|
int uiInit()
|
|
{
|
|
Result rc = 0;
|
|
FT_Error ret = 0;
|
|
|
|
int status = 0;
|
|
bool pl_init = false, romfs_init = false, ft_lib_init = false, ft_std_face_init = false, ft_nintendo_face_init = false;
|
|
|
|
/* Set initial UI state */
|
|
uiState = stateMainMenu;
|
|
menuType = MENUTYPE_MAIN;
|
|
cursor = 0;
|
|
scroll = 0;
|
|
|
|
/* Initialize pl service */
|
|
rc = plInitialize();
|
|
if (R_FAILED(rc))
|
|
{
|
|
error_screen("plInitialize() failed (0x%08X).\n", rc);
|
|
goto out;
|
|
}
|
|
|
|
pl_init = true;
|
|
|
|
/* Retrieve standard shared font */
|
|
rc = plGetSharedFontByType(&standardFont, PlSharedFontType_Standard);
|
|
if (R_FAILED(rc))
|
|
{
|
|
error_screen("plGetSharedFontByType() failed to retrieve standard shared font (0x%08X).\n", rc);
|
|
goto out;
|
|
}
|
|
|
|
/* Retrieve Nintendo shared font */
|
|
rc = plGetSharedFontByType(&nintendoExtFont, PlSharedFontType_NintendoExt);
|
|
if (R_FAILED(rc))
|
|
{
|
|
error_screen("plGetSharedFontByType() failed to retrieve Nintendo shared font (0x%08X).\n", rc);
|
|
goto out;
|
|
}
|
|
|
|
/* Initialize FreeType */
|
|
ret = FT_Init_FreeType(&library);
|
|
if (ret)
|
|
{
|
|
error_screen("FT_Init_FreeType() failed (%d).\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
ft_lib_init = true;
|
|
|
|
/* Create memory face for the standard shared font */
|
|
ret = FT_New_Memory_Face(library, standardFont.address, standardFont.size, 0, &standardFontFace);
|
|
if (ret)
|
|
{
|
|
error_screen("FT_New_Memory_Face() failed to create memory face for the standard shared font (%d).\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
ft_std_face_init = true;
|
|
|
|
/* Create memory face for the Nintendo shared font */
|
|
ret = FT_New_Memory_Face(library, nintendoExtFont.address, nintendoExtFont.size, 0, &nintendoExtFontFace);
|
|
if (ret)
|
|
{
|
|
error_screen("FT_New_Memory_Face() failed to create memory face for the Nintendo shared font (%d).\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
ft_nintendo_face_init = true;
|
|
|
|
/* Set standard shared font character size */
|
|
ret = FT_Set_Char_Size(standardFontFace, 0, CHAR_PT_SIZE * 64, SCREEN_DPI_CNT, SCREEN_DPI_CNT);
|
|
if (ret)
|
|
{
|
|
error_screen("FT_Set_Char_Size() failed to set character size for the standard shared font (%d).\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
/* Set Nintendo shared font character size */
|
|
ret = FT_Set_Char_Size(nintendoExtFontFace, 0, CHAR_PT_SIZE * 64, SCREEN_DPI_CNT, SCREEN_DPI_CNT);
|
|
if (ret)
|
|
{
|
|
error_screen("FT_Set_Char_Size() failed to set character size for the Nintendo shared font (%d).\n", ret);
|
|
goto out;
|
|
}
|
|
|
|
/* Store font height and max width */
|
|
font_height = (standardFontFace->size->metrics.height / 64);
|
|
|
|
/* Prepare additional data needed by the UI functions */
|
|
filenameBuffer = calloc(FILENAME_BUFFER_SIZE, sizeof(char));
|
|
if (!filenameBuffer)
|
|
{
|
|
error_screen("Failed to allocate memory for the filename buffer.\n");
|
|
goto out;
|
|
}
|
|
|
|
/* Mount Application's RomFS */
|
|
rc = romfsInit();
|
|
if (R_FAILED(rc))
|
|
{
|
|
error_screen("romfsInit() failed (0x%08X).\n", rc);
|
|
goto out;
|
|
}
|
|
|
|
romfs_init = true;
|
|
|
|
if (!readCertsFromApplicationRomFs())
|
|
{
|
|
error_screen(strbuf);
|
|
goto out;
|
|
}
|
|
|
|
if (!uiLoadJpgFromFile(dirNormalIconPath, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, &dirNormalIconBuf))
|
|
{
|
|
strcat(strbuf, "Failed to load directory icon (normal).\n");
|
|
error_screen(strbuf);
|
|
goto out;
|
|
}
|
|
|
|
if (!uiLoadJpgFromFile(dirHighlightIconPath, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, &dirHighlightIconBuf))
|
|
{
|
|
strcat(strbuf, "Failed to load directory icon (highlighted).\n");
|
|
error_screen(strbuf);
|
|
goto out;
|
|
}
|
|
|
|
if (!uiLoadJpgFromFile(fileNormalIconPath, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, &fileNormalIconBuf))
|
|
{
|
|
strcat(strbuf, "Failed to load file icon (normal).\n");
|
|
error_screen(strbuf);
|
|
goto out;
|
|
}
|
|
|
|
if (!uiLoadJpgFromFile(fileHighlightIconPath, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, &fileHighlightIconBuf))
|
|
{
|
|
strcat(strbuf, "Failed to load file icon (highlighted).\n");
|
|
error_screen(strbuf);
|
|
goto out;
|
|
}
|
|
|
|
/* Unmount Application's RomFS */
|
|
romfsExit();
|
|
romfs_init = false;
|
|
|
|
/* Reinitialize FS stuff */
|
|
/* Fixes a problem where the file descriptor for the application NRO isn't properly closed */
|
|
/* We'll need to have write access to the NRO if the user runs the update procedure */
|
|
if (!envIsNso())
|
|
{
|
|
fsdevUnmountAll();
|
|
fsExit();
|
|
|
|
rc = fsInitialize();
|
|
if (R_FAILED(rc))
|
|
{
|
|
error_screen("fsInitialize() failed (0x%08X).\n", rc);
|
|
goto out;
|
|
}
|
|
|
|
rc = fsdevMountSdmc();
|
|
if (R_FAILED(rc))
|
|
{
|
|
error_screen("fsdevMountSdmc() failed (0x%08X).\n", rc);
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
/* Create framebuffer */
|
|
framebufferCreate(&fb, nwindowGetDefault(), FB_WIDTH, FB_HEIGHT, PIXEL_FORMAT_RGBA_8888, 2);
|
|
framebufferMakeLinear(&fb);
|
|
|
|
/* Disable screen dimming and auto sleep */
|
|
appletSetMediaPlaybackState(true);
|
|
|
|
/* Get applet type */
|
|
programAppletType = appletGetAppletType();
|
|
|
|
/* Block HOME menu button presses if we're running as a regular application or a system application */
|
|
if (programAppletType == AppletType_Application || programAppletType == AppletType_SystemApplication) appletBeginBlockingHomeButton(0);
|
|
|
|
/* Clear screen */
|
|
uiClearScreen();
|
|
|
|
/* Update free space */
|
|
uiUpdateFreeSpace();
|
|
|
|
/* Set output status */
|
|
status = 1;
|
|
|
|
out:
|
|
if (!status)
|
|
{
|
|
if (fileHighlightIconBuf) free(fileHighlightIconBuf);
|
|
if (fileNormalIconBuf) free(fileNormalIconBuf);
|
|
if (dirHighlightIconBuf) free(dirHighlightIconBuf);
|
|
if (dirNormalIconBuf) free(dirNormalIconBuf);
|
|
|
|
if (romfs_init) romfsExit();
|
|
|
|
if (filenameBuffer) free(filenameBuffer);
|
|
|
|
if (ft_nintendo_face_init) FT_Done_Face(nintendoExtFontFace);
|
|
if (ft_std_face_init) FT_Done_Face(standardFontFace);
|
|
if (ft_lib_init) FT_Done_FreeType(library);
|
|
|
|
if (pl_init) plExit();
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
void uiDeinit()
|
|
{
|
|
/* Unblock HOME menu button presses if we're running as a regular application or a system application */
|
|
if (programAppletType == AppletType_Application || programAppletType == AppletType_SystemApplication) appletEndBlockingHomeButton();
|
|
|
|
/* Enable screen dimming and auto sleep */
|
|
appletSetMediaPlaybackState(false);
|
|
|
|
/* Free framebuffer object */
|
|
framebufferClose(&fb);
|
|
|
|
/* Free directory/file icons */
|
|
free(fileHighlightIconBuf);
|
|
free(fileNormalIconBuf);
|
|
free(dirHighlightIconBuf);
|
|
free(dirNormalIconBuf);
|
|
|
|
/* Free filename buffer */
|
|
free(filenameBuffer);
|
|
|
|
/* Free FreeType resources */
|
|
FT_Done_Face(nintendoExtFontFace);
|
|
FT_Done_Face(standardFontFace);
|
|
FT_Done_FreeType(library);
|
|
|
|
/* Deinitialize pl service */
|
|
plExit();
|
|
}
|
|
|
|
void uiSetState(UIState state)
|
|
{
|
|
uiState = state;
|
|
cursor = 0;
|
|
scroll = 0;
|
|
}
|
|
|
|
UIState uiGetState()
|
|
{
|
|
return uiState;
|
|
}
|
|
|
|
UIResult uiProcess()
|
|
{
|
|
UIResult res = resultNone;
|
|
|
|
int i, j;
|
|
|
|
const char **menu = NULL;
|
|
int menuItemsCount = 0;
|
|
|
|
u32 keysDown;
|
|
u32 keysHeld;
|
|
|
|
int scrollAmount = 0;
|
|
|
|
u32 patch, addon, xpos, ypos, startYPos;
|
|
|
|
char versionStr[128] = {'\0'};
|
|
|
|
uiPrintHeadline();
|
|
loadTitleInfo();
|
|
|
|
if (uiState == stateMainMenu || uiState == stateGameCardMenu || uiState == stateXciDumpMenu || uiState == stateNspDumpMenu || uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu || uiState == stateHfs0Menu || uiState == stateRawHfs0PartitionDumpMenu || uiState == stateHfs0PartitionDataDumpMenu || uiState == stateHfs0BrowserMenu || uiState == stateHfs0Browser || uiState == stateExeFsMenu || uiState == stateExeFsSectionDataDumpMenu || uiState == stateExeFsSectionBrowserMenu || uiState == stateExeFsSectionBrowser || uiState == stateRomFsMenu || uiState == stateRomFsSectionDataDumpMenu || uiState == stateRomFsSectionBrowserMenu || uiState == stateRomFsSectionBrowser || uiState == stateSdCardEmmcMenu || uiState == stateSdCardEmmcTitleMenu || uiState == stateSdCardEmmcOrphanPatchAddOnMenu || uiState == stateUpdateMenu)
|
|
{
|
|
switch(menuType)
|
|
{
|
|
case MENUTYPE_MAIN:
|
|
uiDrawString(appControlsCommon, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
break;
|
|
case MENUTYPE_GAMECARD:
|
|
uiDrawString((!gameCardInserted ? appControlsNoContent : (titleAppCount > 1 ? appControlsGameCardMultiApp : appControlsCommon)), 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
break;
|
|
case MENUTYPE_SDCARD_EMMC:
|
|
if (uiState == stateSdCardEmmcOrphanPatchAddOnMenu)
|
|
{
|
|
uiDrawString(appControlsCommon, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
} else {
|
|
if (titleAppCount)
|
|
{
|
|
if (uiState == stateSdCardEmmcMenu && ((titlePatchCount && checkOrphanPatchOrAddOn(false)) || (titleAddOnCount && checkOrphanPatchOrAddOn(true))))
|
|
{
|
|
uiDrawString(appControlsSdCardEmmcFull, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
} else {
|
|
uiDrawString(appControlsCommon, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
}
|
|
} else {
|
|
if (titlePatchCount || titleAddOnCount)
|
|
{
|
|
uiDrawString(appControlsSdCardEmmcNoApp, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
} else {
|
|
uiDrawString(appControlsNoContent, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
breaks += 2;
|
|
uiDrawString(freeSpaceStr, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
breaks += 2;
|
|
}
|
|
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (!gameCardInserted || hfs0_header == NULL || (hfs0_partition_cnt != GAMECARD_TYPE1_PARTITION_CNT && hfs0_partition_cnt != GAMECARD_TYPE2_PARTITION_CNT) || !titleAppCount || titleAppTitleID == NULL)
|
|
{
|
|
if (gameCardInserted)
|
|
{
|
|
if (hfs0_header != NULL)
|
|
{
|
|
if (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT || hfs0_partition_cnt == GAMECARD_TYPE2_PARTITION_CNT)
|
|
{
|
|
if (titleAppCount > 0)
|
|
{
|
|
uiDrawString("Error: unable to retrieve the gamecard Title ID!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
|
|
if (strlen(gameCardUpdateVersionStr))
|
|
{
|
|
breaks++;
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Bundled FW Update: %s", gameCardUpdateVersionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
breaks++;
|
|
|
|
uiDrawString("In order to be able to dump data from this cartridge, make sure your console is at least on this FW version.", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
}
|
|
} else {
|
|
uiDrawString("Error: gamecard application count is zero!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
}
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Error: unknown root HFS0 header partition count! (%u)", hfs0_partition_cnt);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
}
|
|
} else {
|
|
uiDrawString("Error: unable to get root HFS0 header data!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
}
|
|
} else {
|
|
uiDrawString("Gamecard is not inserted!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
}
|
|
|
|
uiUpdateStatusMsg();
|
|
uiRefreshDisplay();
|
|
|
|
res = resultShowGameCardMenu;
|
|
|
|
hidScanInput();
|
|
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
|
|
|
// Exit
|
|
if (keysDown & KEY_PLUS) res = resultExit;
|
|
|
|
// Back
|
|
if (keysDown & KEY_B)
|
|
{
|
|
res = resultShowMainMenu;
|
|
menuType = MENUTYPE_MAIN;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if (!titleAppCount)
|
|
{
|
|
if (titlePatchCount || titleAddOnCount)
|
|
{
|
|
uiDrawString("No base applications available in the SD card / eMMC storage!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
breaks++;
|
|
|
|
uiDrawString("Use the Y button to dump installed content with missing base applications!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
} else {
|
|
uiDrawString("No titles available in the SD card / eMMC storage!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
}
|
|
|
|
uiUpdateStatusMsg();
|
|
uiRefreshDisplay();
|
|
|
|
res = resultShowSdCardEmmcMenu;
|
|
|
|
hidScanInput();
|
|
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
|
|
|
// Exit
|
|
if (keysDown & KEY_PLUS) res = resultExit;
|
|
|
|
// Back
|
|
if (keysDown & KEY_B)
|
|
{
|
|
res = resultShowMainMenu;
|
|
menuType = MENUTYPE_MAIN;
|
|
}
|
|
|
|
// Dump installed content with missing base application
|
|
if ((titlePatchCount || titleAddOnCount) && (keysDown & KEY_Y))
|
|
{
|
|
res = resultShowSdCardEmmcOrphanPatchAddOnMenu;
|
|
orphanMode = true;
|
|
}
|
|
|
|
return res;
|
|
}
|
|
}
|
|
|
|
if (uiState == stateMainMenu || uiState == stateGameCardMenu || uiState == stateXciDumpMenu || uiState == stateNspDumpMenu || uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu || uiState == stateHfs0Menu || uiState == stateRawHfs0PartitionDumpMenu || uiState == stateHfs0PartitionDataDumpMenu || uiState == stateHfs0BrowserMenu || uiState == stateHfs0Browser || uiState == stateExeFsMenu || uiState == stateExeFsSectionDataDumpMenu || uiState == stateExeFsSectionBrowserMenu || uiState == stateExeFsSectionBrowser || uiState == stateRomFsMenu || uiState == stateRomFsSectionDataDumpMenu || uiState == stateRomFsSectionBrowserMenu || uiState == stateRomFsSectionBrowser || uiState == stateSdCardEmmcMenu || uiState == stateSdCardEmmcTitleMenu || uiState == stateSdCardEmmcOrphanPatchAddOnMenu || uiState == stateUpdateMenu)
|
|
{
|
|
if ((menuType == MENUTYPE_GAMECARD && uiState != stateHfs0Browser && uiState != stateExeFsSectionBrowser && uiState != stateRomFsSectionBrowser) || (menuType == MENUTYPE_SDCARD_EMMC && !orphanMode && uiState != stateSdCardEmmcMenu && uiState != stateExeFsSectionBrowser && uiState != stateRomFsSectionBrowser))
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
uiDrawString("Gamecard is inserted!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
breaks += 2;
|
|
|
|
/*snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Root HFS0 header offset: 0x%016lX", hfs0_offset);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
breaks++;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Root HFS0 header size: 0x%016lX", hfs0_size);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
breaks++;*/
|
|
}
|
|
|
|
/* Print application info */
|
|
xpos = 8;
|
|
ypos = ((breaks * (font_height + (font_height / 4))) + (font_height / 8));
|
|
startYPos = ypos;
|
|
|
|
/* Draw icon */
|
|
if (titleIcon != NULL && titleIcon[selectedAppInfoIndex] != NULL)
|
|
{
|
|
uiDrawIcon(titleIcon[selectedAppInfoIndex], NACP_ICON_DOWNSCALED, NACP_ICON_DOWNSCALED, xpos, ypos + 8);
|
|
xpos += (NACP_ICON_DOWNSCALED + 8);
|
|
ypos += 8;
|
|
}
|
|
|
|
if (titleName != NULL && titleName[selectedAppInfoIndex] != NULL && strlen(titleName[selectedAppInfoIndex]))
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Name: %s", titleName[selectedAppInfoIndex]);
|
|
uiDrawString(strbuf, xpos, ypos, 0, 255, 0);
|
|
ypos += (font_height + (font_height / 4));
|
|
}
|
|
|
|
if (titleAuthor != NULL && titleAuthor[selectedAppInfoIndex] != NULL && strlen(titleAuthor[selectedAppInfoIndex]))
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Developer: %s", titleAuthor[selectedAppInfoIndex]);
|
|
uiDrawString(strbuf, xpos, ypos, 0, 255, 0);
|
|
ypos += (font_height + (font_height / 4));
|
|
}
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Title ID: %016lX", titleAppTitleID[selectedAppInfoIndex]);
|
|
uiDrawString(strbuf, xpos, ypos, 0, 255, 0);
|
|
|
|
if (titlePatchCount > 0)
|
|
{
|
|
u32 patchCnt = 0;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s update(s): v", (menuType == MENUTYPE_GAMECARD ? "Bundled" : "Installed"));
|
|
|
|
for(patch = 0; patch < titlePatchCount; patch++)
|
|
{
|
|
if ((titleAppTitleID[selectedAppInfoIndex] | APPLICATION_PATCH_BITMASK) == titlePatchTitleID[patch])
|
|
{
|
|
if (patchCnt > 0) strcat(strbuf, ", v");
|
|
|
|
convertTitleVersionToDecimal(titlePatchVersion[patch], versionStr, sizeof(versionStr));
|
|
strcat(strbuf, versionStr);
|
|
|
|
patchCnt++;
|
|
}
|
|
}
|
|
|
|
if (patchCnt > 0) uiDrawString(strbuf, (FB_WIDTH / 2) - (FB_WIDTH / 8), ypos, 0, 255, 0);
|
|
}
|
|
|
|
ypos += (font_height + (font_height / 4));
|
|
|
|
if (titleAppVersionStr != NULL && titleAppVersionStr[selectedAppInfoIndex] != NULL && strlen(titleAppVersionStr[selectedAppInfoIndex]))
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Version: %s", titleAppVersionStr[selectedAppInfoIndex]);
|
|
uiDrawString(strbuf, xpos, ypos, 0, 255, 0);
|
|
if (!titleAddOnCount) ypos += (font_height + (font_height / 4));
|
|
}
|
|
|
|
if (titleAddOnCount > 0)
|
|
{
|
|
u32 addOnCnt = 0;
|
|
|
|
for(addon = 0; addon < titleAddOnCount; addon++)
|
|
{
|
|
if ((titleAppTitleID[selectedAppInfoIndex] & APPLICATION_ADDON_BITMASK) == (titleAddOnTitleID[addon] & APPLICATION_ADDON_BITMASK)) addOnCnt++;
|
|
}
|
|
|
|
if (addOnCnt > 0)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s DLC(s): %u", (menuType == MENUTYPE_GAMECARD ? "Bundled" : "Installed"), addOnCnt);
|
|
uiDrawString(strbuf, (FB_WIDTH / 2) - (FB_WIDTH / 8), ypos, 0, 255, 0);
|
|
ypos += (font_height + (font_height / 4));
|
|
}
|
|
}
|
|
|
|
ypos += 8;
|
|
if (xpos > 8 && (ypos - NACP_ICON_DOWNSCALED) < startYPos) ypos += (NACP_ICON_DOWNSCALED - (ypos - startYPos));
|
|
ypos += (font_height + (font_height / 4));
|
|
|
|
breaks += (int)round((double)(ypos - startYPos) / (double)(font_height + (font_height / 4)));
|
|
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Size: %s | Used space: %s", gameCardSizeStr, trimmedCardSizeStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
|
|
if (titleAppCount > 1)
|
|
{
|
|
breaks++;
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Base application count: %u | Base application currently displayed: %u", titleAppCount, selectedAppInfoIndex + 1);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
}
|
|
|
|
breaks++;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Partition count: %u (%s)", hfs0_partition_cnt, GAMECARD_TYPE(hfs0_partition_cnt));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
|
|
if (strlen(gameCardUpdateVersionStr))
|
|
{
|
|
breaks++;
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Bundled FW update: %s", gameCardUpdateVersionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
}
|
|
|
|
if (titlePatchCount > 0)
|
|
{
|
|
breaks++;
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Total bundled update(s): %u", titlePatchCount);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
}
|
|
|
|
if (titleAddOnCount > 0)
|
|
{
|
|
breaks++;
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Total bundled DLC(s): %u", titleAddOnCount);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
}
|
|
|
|
breaks += 2;
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC && orphanMode && (uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu))
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Title ID: %016lX", (uiState == stateNspPatchDumpMenu ? titlePatchTitleID[selectedPatchIndex] : titleAddOnTitleID[selectedAddOnIndex]));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal((uiState == stateNspPatchDumpMenu ? titlePatchVersion[selectedPatchIndex] : titleAddOnVersion[selectedAddOnIndex]), versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Version: %s", versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 0, 255, 0);
|
|
breaks += 2;
|
|
}
|
|
|
|
switch(uiState)
|
|
{
|
|
case stateMainMenu:
|
|
menu = mainMenuItems;
|
|
menuItemsCount = (sizeof(mainMenuItems) / sizeof(mainMenuItems[0]));
|
|
|
|
uiDrawString("Main menu", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateGameCardMenu:
|
|
menu = gameCardMenuItems;
|
|
menuItemsCount = (sizeof(gameCardMenuItems) / sizeof(gameCardMenuItems[0]));
|
|
|
|
uiDrawString(mainMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateXciDumpMenu:
|
|
menu = xciDumpMenuItems;
|
|
menuItemsCount = (sizeof(xciDumpMenuItems) / sizeof(xciDumpMenuItems[0]));
|
|
|
|
uiDrawString(gameCardMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateNspDumpMenu:
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
menu = nspDumpGameCardMenuItems;
|
|
menuItemsCount = (sizeof(nspDumpGameCardMenuItems) / sizeof(nspDumpGameCardMenuItems[0]));
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
menu = nspDumpSdCardEmmcMenuItems;
|
|
menuItemsCount = (sizeof(nspDumpSdCardEmmcMenuItems) / sizeof(nspDumpSdCardEmmcMenuItems[0]));
|
|
}
|
|
|
|
uiDrawString(gameCardMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateNspAppDumpMenu:
|
|
menu = nspAppDumpMenuItems;
|
|
menuItemsCount = (sizeof(nspAppDumpMenuItems) / sizeof(nspAppDumpMenuItems[0]));
|
|
|
|
uiDrawString(nspDumpGameCardMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateNspPatchDumpMenu:
|
|
menu = nspPatchDumpMenuItems;
|
|
menuItemsCount = (sizeof(nspPatchDumpMenuItems) / sizeof(nspPatchDumpMenuItems[0]));
|
|
|
|
uiDrawString((menuType == MENUTYPE_GAMECARD ? nspDumpGameCardMenuItems[1] : nspDumpSdCardEmmcMenuItems[1]), 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateNspAddOnDumpMenu:
|
|
menu = nspAddOnDumpMenuItems;
|
|
menuItemsCount = sizeof(nspAddOnDumpMenuItems) / sizeof(nspAddOnDumpMenuItems[0]);
|
|
|
|
uiDrawString((menuType == MENUTYPE_GAMECARD ? nspDumpGameCardMenuItems[2] : nspDumpSdCardEmmcMenuItems[2]), 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateHfs0Menu:
|
|
menu = hfs0MenuItems;
|
|
menuItemsCount = (sizeof(hfs0MenuItems) / sizeof(hfs0MenuItems[0]));
|
|
|
|
uiDrawString(gameCardMenuItems[2], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateRawHfs0PartitionDumpMenu:
|
|
case stateHfs0PartitionDataDumpMenu:
|
|
menu = (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? hfs0PartitionDumpType1MenuItems : hfs0PartitionDumpType2MenuItems);
|
|
menuItemsCount = (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? (sizeof(hfs0PartitionDumpType1MenuItems) / sizeof(hfs0PartitionDumpType1MenuItems[0])) : (sizeof(hfs0PartitionDumpType2MenuItems) / sizeof(hfs0PartitionDumpType2MenuItems[0])));
|
|
|
|
uiDrawString((uiState == stateRawHfs0PartitionDumpMenu ? hfs0MenuItems[0] : hfs0MenuItems[1]), 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateHfs0BrowserMenu:
|
|
menu = (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? hfs0BrowserType1MenuItems : hfs0BrowserType2MenuItems);
|
|
menuItemsCount = (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? (sizeof(hfs0BrowserType1MenuItems) / sizeof(hfs0BrowserType1MenuItems[0])) : (sizeof(hfs0BrowserType2MenuItems) / sizeof(hfs0BrowserType2MenuItems[0])));
|
|
|
|
uiDrawString(hfs0MenuItems[2], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateHfs0Browser:
|
|
menu = (const char**)filenames;
|
|
menuItemsCount = filenamesCount;
|
|
|
|
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? hfs0BrowserType1MenuItems[selectedPartitionIndex] : hfs0BrowserType2MenuItems[selectedPartitionIndex]), 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Entry count: %d | Current entry: %d", menuItemsCount, cursor + 1);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
|
|
break;
|
|
case stateExeFsMenu:
|
|
menu = exeFsMenuItems;
|
|
menuItemsCount = (sizeof(exeFsMenuItems) / sizeof(exeFsMenuItems[0]));
|
|
|
|
uiDrawString(gameCardMenuItems[3], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateExeFsSectionDataDumpMenu:
|
|
menu = exeFsSectionDumpMenuItems;
|
|
menuItemsCount = (sizeof(exeFsSectionDumpMenuItems) / sizeof(exeFsSectionDumpMenuItems[0]));
|
|
|
|
uiDrawString(exeFsMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateExeFsSectionBrowserMenu:
|
|
menu = exeFsSectionBrowserMenuItems;
|
|
menuItemsCount = (sizeof(exeFsSectionBrowserMenuItems) / sizeof(exeFsSectionBrowserMenuItems[0]));
|
|
|
|
uiDrawString(exeFsMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateExeFsSectionBrowser:
|
|
menu = (const char**)filenames;
|
|
menuItemsCount = filenamesCount;
|
|
|
|
uiDrawString(exeFsMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", exeFsSectionBrowserMenuItems[1], titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Entry count: %d | Current entry: %d", menuItemsCount, cursor + 1);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
|
|
break;
|
|
case stateRomFsMenu:
|
|
menu = romFsMenuItems;
|
|
menuItemsCount = (sizeof(romFsMenuItems) / sizeof(romFsMenuItems[0]));
|
|
|
|
uiDrawString(gameCardMenuItems[4], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateRomFsSectionDataDumpMenu:
|
|
menu = romFsSectionDumpMenuItems;
|
|
menuItemsCount = (sizeof(romFsSectionDumpMenuItems) / sizeof(romFsSectionDumpMenuItems[0]));
|
|
|
|
uiDrawString(romFsMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateRomFsSectionBrowserMenu:
|
|
menu = romFsSectionBrowserMenuItems;
|
|
menuItemsCount = (sizeof(romFsSectionBrowserMenuItems) / sizeof(romFsSectionBrowserMenuItems[0]));
|
|
|
|
uiDrawString(romFsMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateRomFsSectionBrowser:
|
|
menu = (const char**)filenames;
|
|
menuItemsCount = filenamesCount;
|
|
|
|
uiDrawString(romFsMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", romFsSectionBrowserMenuItems[1], titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Path: romfs:%s", curRomFsPath);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
if (cursor > 0)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Entry count: %d | Current entry: %d", menuItemsCount - 1, cursor);
|
|
} else {
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Entry count: %d", menuItemsCount - 1);
|
|
}
|
|
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
|
|
break;
|
|
case stateSdCardEmmcMenu:
|
|
menu = (const char**)titleName;
|
|
menuItemsCount = (int)titleAppCount;
|
|
|
|
uiDrawString(mainMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
if (menuItemsCount)
|
|
{
|
|
breaks += 2;
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Title count: %d | Current title: %d", menuItemsCount, cursor + 1);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
}
|
|
|
|
break;
|
|
case stateSdCardEmmcTitleMenu:
|
|
menu = sdCardEmmcMenuItems;
|
|
menuItemsCount = (sizeof(sdCardEmmcMenuItems) / sizeof(sdCardEmmcMenuItems[0]));
|
|
|
|
uiDrawString(mainMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
case stateSdCardEmmcOrphanPatchAddOnMenu:
|
|
if (orphanEntries == NULL) generateOrphanPatchOrAddOnList();
|
|
|
|
menu = (const char**)filenames;
|
|
menuItemsCount = filenamesCount;
|
|
|
|
uiDrawString("Dump installed content with missing base application", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
if (menuItemsCount)
|
|
{
|
|
breaks += 2;
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Title count: %d | Current title: %d", menuItemsCount, cursor + 1);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 255, 255);
|
|
}
|
|
|
|
break;
|
|
case stateUpdateMenu:
|
|
menu = updateMenuItems;
|
|
menuItemsCount = sizeof(updateMenuItems) / sizeof(updateMenuItems[0]);
|
|
|
|
uiDrawString(mainMenuItems[2], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (menu && menuItemsCount)
|
|
{
|
|
breaks += 2;
|
|
|
|
j = 0;
|
|
highlight = false;
|
|
|
|
for(i = scroll; i < menuItemsCount; i++, j++)
|
|
{
|
|
if (((uiState != stateSdCardEmmcMenu && uiState != stateSdCardEmmcOrphanPatchAddOnMenu && uiState != stateHfs0Browser && uiState != stateExeFsSectionBrowser && uiState != stateRomFsSectionBrowser) && j >= COMMON_MAX_ELEMENTS) || (uiState == stateSdCardEmmcMenu && j >= SDCARD_MAX_ELEMENTS) || (uiState == stateSdCardEmmcOrphanPatchAddOnMenu && j >= ORPHAN_MAX_ELEMENTS) || (uiState == stateHfs0Browser && j >= HFS0_MAX_ELEMENTS) || ((uiState == stateExeFsSectionBrowser || uiState == stateRomFsSectionBrowser) && j >= ROMFS_MAX_ELEMENTS)) break;
|
|
|
|
// Avoid printing the "Create directory with archive bit set" option if "Split output dump" is disabled
|
|
if (uiState == stateXciDumpMenu && i == 2 && !isFat32)
|
|
{
|
|
j--;
|
|
continue;
|
|
}
|
|
|
|
// Avoid printing the "Dump bundled update NSP" option in the NSP dump menu if we're dealing with a gamecard and it doesn't include any bundled updates, or if we're dealing with a SD/eMMC title without installed updates
|
|
// Also avoid printing the "Dump bundled DLC NSP" option in the NSP dump menu if we're dealing with a gamecard and it doesn't include any bundled DLCs, or if we're dealing with a SD/eMMC title without installed DLCs
|
|
if (uiState == stateNspDumpMenu)
|
|
{
|
|
if (i == 1)
|
|
{
|
|
if (!titlePatchCount || (menuType == MENUTYPE_SDCARD_EMMC && !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false))) continue;
|
|
} else
|
|
if (i == 2)
|
|
{
|
|
if (!titleAddOnCount || (menuType == MENUTYPE_SDCARD_EMMC && !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, true))) continue;
|
|
|
|
if (!titlePatchCount || (menuType == MENUTYPE_SDCARD_EMMC && !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false))) j--;
|
|
}
|
|
}
|
|
|
|
// Avoid printing the "Remove console specific data" and "Generate ticket-less dump" options in the NSP dump menus if we're dealing with a gamecard title
|
|
if (menuType == MENUTYPE_GAMECARD && (uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu) && (i == 3 || i == 4))
|
|
{
|
|
j--;
|
|
continue;
|
|
}
|
|
|
|
// Avoid printing the "Generate ticket-less dump" option in the NSP dump menus if we're dealing with a SD/eMMC title and the "Remove console specific data" option is disabled
|
|
if (menuType == MENUTYPE_SDCARD_EMMC && (uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu) && i == 4 && !removeConsoleData)
|
|
{
|
|
j--;
|
|
continue;
|
|
}
|
|
|
|
// Avoid printing the parent directory entry ("..") in the RomFS browser if we're currently at the root directory
|
|
if (uiState == stateRomFsSectionBrowser && i == 0 && strlen(curRomFsPath) <= 1)
|
|
{
|
|
j--;
|
|
continue;
|
|
}
|
|
|
|
xpos = 8;
|
|
ypos = ((breaks * (font_height + (font_height / 4))) + (uiState == stateSdCardEmmcMenu ? (j * (NACP_ICON_DOWNSCALED + 12)) : (j * (font_height + 12))) + 6);
|
|
|
|
int font_r = 255, font_g = 255, font_b = 255;
|
|
|
|
if (i == cursor)
|
|
{
|
|
highlight = true;
|
|
|
|
uiFill(0, (ypos + 8) - 6, FB_WIDTH, (uiState == stateSdCardEmmcMenu ? (NACP_ICON_DOWNSCALED + 12) : (font_height + 12)), HIGHLIGHT_BG_COLOR_R, HIGHLIGHT_BG_COLOR_G, HIGHLIGHT_BG_COLOR_B);
|
|
|
|
font_r = HIGHLIGHT_FONT_COLOR_R;
|
|
font_g = HIGHLIGHT_FONT_COLOR_G;
|
|
font_b = HIGHLIGHT_FONT_COLOR_B;
|
|
}
|
|
|
|
if (uiState == stateSdCardEmmcMenu)
|
|
{
|
|
if (titleIcon != NULL && titleIcon[i] != NULL)
|
|
{
|
|
uiDrawIcon(titleIcon[i], NACP_ICON_DOWNSCALED, NACP_ICON_DOWNSCALED, xpos, ypos + 8);
|
|
|
|
xpos += (NACP_ICON_DOWNSCALED + 8);
|
|
}
|
|
|
|
ypos += ((NACP_ICON_DOWNSCALED / 2) - (font_height / 2));
|
|
} else
|
|
if (uiState == stateHfs0Browser || uiState == stateExeFsSectionBrowser || uiState == stateRomFsSectionBrowser)
|
|
{
|
|
u8 *icon = (highlight ? (uiState == stateRomFsSectionBrowser ? (romFsBrowserEntries[i].type == ROMFS_ENTRY_DIR ? dirHighlightIconBuf : fileHighlightIconBuf) : fileHighlightIconBuf) : (uiState == stateRomFsSectionBrowser ? (romFsBrowserEntries[i].type == ROMFS_ENTRY_DIR ? dirNormalIconBuf : fileNormalIconBuf) : fileNormalIconBuf));
|
|
|
|
uiDrawIcon(icon, BROWSER_ICON_DIMENSION, BROWSER_ICON_DIMENSION, xpos, ypos + 8);
|
|
|
|
xpos += (BROWSER_ICON_DIMENSION + 8);
|
|
}
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), menu[i]);
|
|
u32 strWidth = uiGetStrWidth(strbuf);
|
|
|
|
if ((xpos + strWidth) >= (FB_WIDTH - (font_height * 5)))
|
|
{
|
|
while((xpos + strWidth) >= (FB_WIDTH - (font_height * 5)))
|
|
{
|
|
u32 charWidth = uiGetStrWidth(&(strbuf[strlen(strbuf) - 1]));
|
|
strbuf[strlen(strbuf) - 1] = '\0';
|
|
strWidth -= charWidth;
|
|
}
|
|
|
|
strcat(strbuf, "...");
|
|
}
|
|
|
|
uiDrawString(strbuf, xpos, ypos, font_r, font_g, font_b);
|
|
|
|
// Print XCI dump menu settings values
|
|
if (uiState == stateXciDumpMenu && i > 0)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 1: // Split output dump (FAT32 support)
|
|
uiDrawString((isFat32 ? "Yes" : "No"), OPTIONS_X_POS, ypos, (isFat32 ? 0 : 255), (isFat32 ? 255 : 0), 0);
|
|
break;
|
|
case 2: // Create directory with archive bit set
|
|
uiDrawString((setXciArchiveBit ? "Yes" : "No"), OPTIONS_X_POS, ypos, (setXciArchiveBit ? 0 : 255), (setXciArchiveBit ? 255 : 0), 0);
|
|
break;
|
|
case 3: // Dump certificate
|
|
uiDrawString((dumpCert ? "Yes" : "No"), OPTIONS_X_POS, ypos, (dumpCert ? 0 : 255), (dumpCert ? 255 : 0), 0);
|
|
break;
|
|
case 4: // Trim output dump
|
|
uiDrawString((trimDump ? "Yes" : "No"), OPTIONS_X_POS, ypos, (trimDump ? 0 : 255), (trimDump ? 255 : 0), 0);
|
|
break;
|
|
case 5: // CRC32 checksum calculation + dump verification
|
|
uiDrawString((calcCrc ? "Yes" : "No"), OPTIONS_X_POS, ypos, (calcCrc ? 0 : 255), (calcCrc ? 255 : 0), 0);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Print NSP dump menus settings values
|
|
if ((uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu) && i > 0)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 1: // Split output dump (FAT32 support)
|
|
uiDrawString((isFat32 ? "Yes" : "No"), OPTIONS_X_POS, ypos, (isFat32 ? 0 : 255), (isFat32 ? 255 : 0), 0);
|
|
break;
|
|
case 2: // CRC32 checksum calculation
|
|
uiDrawString((calcCrc ? "Yes" : "No"), OPTIONS_X_POS, ypos, (calcCrc ? 0 : 255), (calcCrc ? 255 : 0), 0);
|
|
break;
|
|
case 3: // Remove console specific data
|
|
uiDrawString((removeConsoleData ? "Yes" : "No"), OPTIONS_X_POS, ypos, (removeConsoleData ? 0 : 255), (removeConsoleData ? 255 : 0), 0);
|
|
break;
|
|
case 4: // Generate ticket-less dump
|
|
uiDrawString((tiklessDump ? "Yes" : "No"), OPTIONS_X_POS, ypos, (tiklessDump ? 0 : 255), (tiklessDump ? 255 : 0), 0);
|
|
break;
|
|
case 5: // Bundled application/update/DLC to dump
|
|
if (uiState == stateNspAppDumpMenu)
|
|
{
|
|
// Print application name
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s v%s", titleName[selectedAppIndex], versionStr);
|
|
} else
|
|
if (uiState == stateNspPatchDumpMenu)
|
|
{
|
|
// Find a matching application to print its name
|
|
// Otherwise, just print the Title ID
|
|
retrieveDescriptionForPatchOrAddOn(titlePatchTitleID[selectedPatchIndex], titlePatchVersion[selectedPatchIndex], false, NULL);
|
|
} else
|
|
if (uiState == stateNspAddOnDumpMenu)
|
|
{
|
|
// Find a matching application to print its name and Title ID
|
|
// Otherwise, just print the Title ID
|
|
retrieveDescriptionForPatchOrAddOn(titleAddOnTitleID[selectedAddOnIndex], titleAddOnVersion[selectedAddOnIndex], true, NULL);
|
|
}
|
|
|
|
uiDrawString(strbuf, OPTIONS_X_POS, ypos, 255, 255, 255);
|
|
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (i == 2)
|
|
{
|
|
if (calcCrc)
|
|
{
|
|
uiDrawString("This takes extra time after the NSP dump has been completed!", FB_WIDTH / 2, ypos, 255, 255, 255);
|
|
} else {
|
|
uiFill(FB_WIDTH / 2, (ypos + 8) - 6, FB_WIDTH / 2, font_height + 12, (highlight ? HIGHLIGHT_BG_COLOR_R : BG_COLOR_RGB), (highlight ? HIGHLIGHT_BG_COLOR_G : BG_COLOR_RGB), (highlight ? HIGHLIGHT_BG_COLOR_B : BG_COLOR_RGB));
|
|
}
|
|
}
|
|
}
|
|
|
|
// Print ExeFS/RomFS menus settings values
|
|
if ((uiState == stateExeFsSectionDataDumpMenu || uiState == stateExeFsSectionBrowserMenu || uiState == stateRomFsSectionDataDumpMenu || uiState == stateRomFsSectionBrowserMenu) && i > 0)
|
|
{
|
|
switch(i)
|
|
{
|
|
case 1: // Bundled application to dump/browse
|
|
// Print application name
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s v%s", titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, OPTIONS_X_POS, ypos, 255, 255, 255);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (i == cursor) highlight = false;
|
|
}
|
|
} else {
|
|
if (uiState == stateSdCardEmmcOrphanPatchAddOnMenu)
|
|
{
|
|
breaks += 2;
|
|
uiDrawString("No orphan updates/DLCs available in the SD card / eMMC storage!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 255, 0, 0);
|
|
}
|
|
}
|
|
|
|
uiUpdateStatusMsg();
|
|
uiRefreshDisplay();
|
|
|
|
hidScanInput();
|
|
keysDown = hidKeysDown(CONTROLLER_P1_AUTO);
|
|
keysHeld = hidKeysHeld(CONTROLLER_P1_AUTO);
|
|
|
|
// Exit
|
|
if (keysDown & KEY_PLUS) res = resultExit;
|
|
|
|
// Process key inputs only if the UI state hasn't been changed
|
|
if (res == resultNone)
|
|
{
|
|
// Process base application info change
|
|
if (menuType == MENUTYPE_GAMECARD && titleAppCount > 1 && uiState != stateHfs0Browser && uiState != stateExeFsSectionBrowser && uiState != stateRomFsSectionBrowser)
|
|
{
|
|
if ((keysDown & KEY_L) || (keysDown & KEY_ZL))
|
|
{
|
|
if (selectedAppInfoIndex > 0)
|
|
{
|
|
selectedAppInfoIndex--;
|
|
} else {
|
|
selectedAppInfoIndex = 0;
|
|
}
|
|
}
|
|
|
|
if ((keysDown & KEY_R) || (keysDown & KEY_ZR))
|
|
{
|
|
selectedAppInfoIndex++;
|
|
if (selectedAppInfoIndex >= titleAppCount) selectedAppInfoIndex = (titleAppCount - 1);
|
|
}
|
|
}
|
|
|
|
if (uiState == stateXciDumpMenu)
|
|
{
|
|
// Select
|
|
if ((keysDown & KEY_A) && cursor == 0) res = resultDumpXci;
|
|
|
|
// Back
|
|
if (keysDown & KEY_B) res = resultShowGameCardMenu;
|
|
|
|
// Change option to false
|
|
if (keysDown & KEY_LEFT)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 1: // Split output dump (FAT32 support)
|
|
isFat32 = setXciArchiveBit = false;
|
|
break;
|
|
case 2: // Create directory with archive bit set
|
|
setXciArchiveBit = false;
|
|
break;
|
|
case 3: // Dump certificate
|
|
dumpCert = false;
|
|
break;
|
|
case 4: // Trim output dump
|
|
trimDump = false;
|
|
break;
|
|
case 5: // CRC32 checksum calculation + dump verification
|
|
calcCrc = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Change option to true
|
|
if (keysDown & KEY_RIGHT)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 1: // Split output dump (FAT32 support)
|
|
isFat32 = true;
|
|
break;
|
|
case 2: // Create directory with archive bit set
|
|
setXciArchiveBit = true;
|
|
break;
|
|
case 3: // Dump certificate
|
|
dumpCert = true;
|
|
break;
|
|
case 4: // Trim output dump
|
|
trimDump = true;
|
|
break;
|
|
case 5: // CRC32 checksum calculation + dump verification
|
|
calcCrc = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Go up
|
|
if ((keysDown & KEY_DUP) || (keysDown & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
|
|
|
|
// Go down
|
|
if ((keysDown & KEY_DDOWN) || (keysDown & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
|
|
} else
|
|
if (uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu)
|
|
{
|
|
// Select
|
|
if ((keysDown & KEY_A) && cursor == 0)
|
|
{
|
|
selectedNspDumpType = (uiState == stateNspAppDumpMenu ? DUMP_APP_NSP : (uiState == stateNspPatchDumpMenu ? DUMP_PATCH_NSP : DUMP_ADDON_NSP));
|
|
res = resultDumpNsp;
|
|
}
|
|
|
|
// Back
|
|
if (keysDown & KEY_B)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (uiState == stateNspAppDumpMenu && !titlePatchCount && !titleAddOnCount)
|
|
{
|
|
res = resultShowGameCardMenu;
|
|
} else {
|
|
res = resultShowNspDumpMenu;
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if (!orphanMode)
|
|
{
|
|
if (uiState == stateNspAppDumpMenu && (!titlePatchCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false)) && (!titleAddOnCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, true)))
|
|
{
|
|
res = resultShowSdCardEmmcTitleMenu;
|
|
} else {
|
|
res = resultShowNspDumpMenu;
|
|
}
|
|
} else {
|
|
res = resultShowSdCardEmmcOrphanPatchAddOnMenu;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Change option to false
|
|
if (keysDown & KEY_LEFT)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 1: // Split output dump (FAT32 support)
|
|
isFat32 = false;
|
|
break;
|
|
case 2: // CRC32 checksum calculation
|
|
calcCrc = false;
|
|
break;
|
|
case 3: // Remove console specific data
|
|
removeConsoleData = tiklessDump = false;
|
|
break;
|
|
case 4: // Generate ticket-less dump
|
|
tiklessDump = false;
|
|
break;
|
|
case 5: // Bundled application/update/DLC to dump
|
|
if (uiState == stateNspAppDumpMenu)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (selectedAppIndex > 0)
|
|
{
|
|
selectedAppIndex--;
|
|
} else {
|
|
selectedAppIndex = 0;
|
|
}
|
|
}
|
|
} else
|
|
if (uiState == stateNspPatchDumpMenu)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (selectedPatchIndex > 0)
|
|
{
|
|
selectedPatchIndex--;
|
|
} else {
|
|
selectedPatchIndex = 0;
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if (!orphanMode)
|
|
{
|
|
bool foundMatch = false;
|
|
u32 startIndex = selectedPatchIndex;
|
|
int curIndex = ((int)selectedPatchIndex - 1);
|
|
|
|
while(curIndex >= 0)
|
|
{
|
|
if (checkIfPatchOrAddOnBelongToBaseApplication((u32)curIndex, selectedAppInfoIndex, false))
|
|
{
|
|
selectedPatchIndex = (u32)curIndex;
|
|
foundMatch = true;
|
|
break;
|
|
}
|
|
|
|
curIndex--;
|
|
}
|
|
|
|
if (!foundMatch) selectedPatchIndex = startIndex;
|
|
}
|
|
}
|
|
} else
|
|
if (uiState == stateNspAddOnDumpMenu)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (selectedAddOnIndex > 0)
|
|
{
|
|
selectedAddOnIndex--;
|
|
} else {
|
|
selectedAddOnIndex = 0;
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if (!orphanMode)
|
|
{
|
|
bool foundMatch = false;
|
|
u32 startIndex = selectedAddOnIndex;
|
|
int curIndex = ((int)selectedAddOnIndex - 1);
|
|
|
|
while(curIndex >= 0)
|
|
{
|
|
if (checkIfPatchOrAddOnBelongToBaseApplication((u32)curIndex, selectedAppInfoIndex, true))
|
|
{
|
|
selectedAddOnIndex = (u32)curIndex;
|
|
foundMatch = true;
|
|
break;
|
|
}
|
|
|
|
curIndex--;
|
|
}
|
|
|
|
if (!foundMatch) selectedAddOnIndex = startIndex;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Change option to true
|
|
if (keysDown & KEY_RIGHT)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 1: // Split output dump (FAT32 support)
|
|
isFat32 = true;
|
|
break;
|
|
case 2: // CRC32 checksum calculation
|
|
calcCrc = true;
|
|
break;
|
|
case 3: // Remove console specific data
|
|
removeConsoleData = true;
|
|
break;
|
|
case 4: // Generate ticket-less dump
|
|
tiklessDump = true;
|
|
break;
|
|
case 5: // Bundled application/update/DLC to dump
|
|
if (uiState == stateNspAppDumpMenu)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (titleAppCount > 1)
|
|
{
|
|
selectedAppIndex++;
|
|
if (selectedAppIndex >= titleAppCount) selectedAppIndex = (titleAppCount - 1);
|
|
}
|
|
}
|
|
} else
|
|
if (uiState == stateNspPatchDumpMenu)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (titlePatchCount > 1)
|
|
{
|
|
selectedPatchIndex++;
|
|
if (selectedPatchIndex >= titlePatchCount) selectedPatchIndex = (titlePatchCount - 1);
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if (!orphanMode)
|
|
{
|
|
bool foundMatch = false;
|
|
u32 startIndex = selectedPatchIndex;
|
|
|
|
selectedPatchIndex++;
|
|
|
|
while(selectedPatchIndex < titlePatchCount)
|
|
{
|
|
if (checkIfPatchOrAddOnBelongToBaseApplication(selectedPatchIndex, selectedAppInfoIndex, false))
|
|
{
|
|
foundMatch = true;
|
|
break;
|
|
}
|
|
|
|
selectedPatchIndex++;
|
|
}
|
|
|
|
if (!foundMatch) selectedPatchIndex = startIndex;
|
|
}
|
|
}
|
|
} else
|
|
if (uiState == stateNspAddOnDumpMenu)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (titleAddOnCount > 1)
|
|
{
|
|
selectedAddOnIndex++;
|
|
if (selectedAddOnIndex >= titleAddOnCount) selectedAddOnIndex = (titleAddOnCount - 1);
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if (!orphanMode)
|
|
{
|
|
bool foundMatch = false;
|
|
u32 startIndex = selectedAddOnIndex;
|
|
|
|
selectedAddOnIndex++;
|
|
|
|
while(selectedAddOnIndex < titleAddOnCount)
|
|
{
|
|
if (checkIfPatchOrAddOnBelongToBaseApplication(selectedAddOnIndex, selectedAppInfoIndex, true))
|
|
{
|
|
foundMatch = true;
|
|
break;
|
|
}
|
|
|
|
selectedAddOnIndex++;
|
|
}
|
|
|
|
if (!foundMatch) selectedAddOnIndex = startIndex;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Go up
|
|
if ((keysDown & KEY_DUP) || (keysDown & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
|
|
|
|
// Go down
|
|
if ((keysDown & KEY_DDOWN) || (keysDown & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
|
|
} else
|
|
if (uiState == stateExeFsSectionDataDumpMenu || uiState == stateExeFsSectionBrowserMenu || uiState == stateRomFsSectionDataDumpMenu || uiState == stateRomFsSectionBrowserMenu)
|
|
{
|
|
// Select
|
|
if ((keysDown & KEY_A) && cursor == 0)
|
|
{
|
|
if (uiState == stateExeFsSectionDataDumpMenu || uiState == stateExeFsSectionBrowserMenu)
|
|
{
|
|
res = (uiState == stateExeFsSectionDataDumpMenu ? resultDumpExeFsSectionData : resultExeFsSectionBrowserGetList);
|
|
} else
|
|
if (uiState == stateRomFsSectionDataDumpMenu || uiState == stateRomFsSectionBrowserMenu)
|
|
{
|
|
res = (uiState == stateRomFsSectionDataDumpMenu ? resultDumpRomFsSectionData : resultRomFsSectionBrowserGetEntries);
|
|
}
|
|
}
|
|
|
|
// Back
|
|
if (keysDown & KEY_B) res = (menuType == MENUTYPE_GAMECARD ? resultShowGameCardMenu : resultShowSdCardEmmcTitleMenu);
|
|
|
|
// Change option to false
|
|
if (keysDown & KEY_LEFT)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 1: // Bundled application to dump/browse
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (selectedAppIndex > 0)
|
|
{
|
|
selectedAppIndex--;
|
|
} else {
|
|
selectedAppIndex = 0;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Change option to true
|
|
if (keysDown & KEY_RIGHT)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 1: // Bundled application to dump/browse
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if (titleAppCount > 1)
|
|
{
|
|
selectedAppIndex++;
|
|
if (selectedAppIndex >= titleAppCount) selectedAppIndex = (titleAppCount - 1);
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Go up
|
|
if ((keysDown & KEY_DUP) || (keysDown & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
|
|
|
|
// Go down
|
|
if ((keysDown & KEY_DDOWN) || (keysDown & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
|
|
} else {
|
|
// Select
|
|
if (keysDown & KEY_A)
|
|
{
|
|
if (uiState == stateMainMenu)
|
|
{
|
|
selectedAppInfoIndex = 0;
|
|
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
res = resultShowGameCardMenu;
|
|
menuType = MENUTYPE_GAMECARD;
|
|
break;
|
|
case 1:
|
|
res = resultShowSdCardEmmcMenu;
|
|
menuType = MENUTYPE_SDCARD_EMMC;
|
|
break;
|
|
case 2:
|
|
res = resultShowUpdateMenu;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
if (uiState == stateGameCardMenu)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
res = resultShowXciDumpMenu;
|
|
|
|
// Reset options to their default values
|
|
isFat32 = false;
|
|
dumpCert = false;
|
|
trimDump = false;
|
|
calcCrc = true;
|
|
setXciArchiveBit = false;
|
|
break;
|
|
case 1:
|
|
if (!titlePatchCount && !titleAddOnCount)
|
|
{
|
|
res = resultShowNspAppDumpMenu;
|
|
|
|
// Reset options to their default values
|
|
isFat32 = false;
|
|
calcCrc = false;
|
|
removeConsoleData = false;
|
|
tiklessDump = false;
|
|
selectedAppIndex = 0;
|
|
} else {
|
|
res = resultShowNspDumpMenu;
|
|
}
|
|
break;
|
|
case 2:
|
|
res = resultShowHfs0Menu;
|
|
break;
|
|
case 3:
|
|
res = resultShowExeFsMenu;
|
|
break;
|
|
case 4:
|
|
res = resultShowRomFsMenu;
|
|
break;
|
|
case 5:
|
|
res = resultDumpGameCardCertificate;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
if (uiState == stateNspDumpMenu)
|
|
{
|
|
// Reset options to their default values
|
|
isFat32 = false;
|
|
calcCrc = false;
|
|
removeConsoleData = false;
|
|
tiklessDump = false;
|
|
|
|
selectedAppIndex = 0;
|
|
selectedPatchIndex = 0;
|
|
selectedAddOnIndex = 0;
|
|
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
res = resultShowNspAppDumpMenu;
|
|
if (menuType == MENUTYPE_SDCARD_EMMC) selectedAppIndex = selectedAppInfoIndex;
|
|
break;
|
|
case 1:
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
res = (titlePatchCount > 0 ? resultShowNspPatchDumpMenu : resultShowNspAddOnDumpMenu);
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if (titlePatchCount > 0 && checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false))
|
|
{
|
|
res = resultShowNspPatchDumpMenu;
|
|
selectedPatchIndex = retrieveFirstPatchOrAddOnIndexFromBaseApplication(selectedAppInfoIndex, false);
|
|
} else {
|
|
res = resultShowNspAddOnDumpMenu;
|
|
selectedAddOnIndex = retrieveFirstPatchOrAddOnIndexFromBaseApplication(selectedAppInfoIndex, true);
|
|
}
|
|
}
|
|
break;
|
|
case 2:
|
|
res = resultShowNspAddOnDumpMenu;
|
|
selectedAddOnIndex = retrieveFirstPatchOrAddOnIndexFromBaseApplication(selectedAppInfoIndex, true);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
if (uiState == stateHfs0Menu)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
res = resultShowRawHfs0PartitionDumpMenu;
|
|
break;
|
|
case 1:
|
|
res = resultShowHfs0PartitionDataDumpMenu;
|
|
break;
|
|
case 2:
|
|
res = resultShowHfs0BrowserMenu;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
if (uiState == stateRawHfs0PartitionDumpMenu)
|
|
{
|
|
// Save selected partition index
|
|
selectedPartitionIndex = (u32)cursor;
|
|
res = resultDumpRawHfs0Partition;
|
|
} else
|
|
if (uiState == stateHfs0PartitionDataDumpMenu)
|
|
{
|
|
// Save selected partition index
|
|
selectedPartitionIndex = (u32)cursor;
|
|
res = resultDumpHfs0PartitionData;
|
|
} else
|
|
if (uiState == stateHfs0BrowserMenu)
|
|
{
|
|
// Save selected partition index
|
|
selectedPartitionIndex = (u32)cursor;
|
|
res = resultHfs0BrowserGetList;
|
|
} else
|
|
if (uiState == stateHfs0Browser)
|
|
{
|
|
// Save selected file index
|
|
selectedFileIndex = (u32)cursor;
|
|
res = resultHfs0BrowserCopyFile;
|
|
} else
|
|
if (uiState == stateExeFsMenu)
|
|
{
|
|
// Reset option to its default value
|
|
selectedAppIndex = (menuType == MENUTYPE_GAMECARD ? 0 : selectedAppInfoIndex);
|
|
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowExeFsSectionDataDumpMenu : resultDumpExeFsSectionData);
|
|
break;
|
|
case 1:
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowExeFsSectionBrowserMenu : resultExeFsSectionBrowserGetList);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
if (uiState == stateExeFsSectionBrowser)
|
|
{
|
|
if (menu && menuItemsCount)
|
|
{
|
|
// Save selected file index
|
|
selectedFileIndex = (u32)cursor;
|
|
res = resultExeFsSectionBrowserCopyFile;
|
|
}
|
|
} else
|
|
if (uiState == stateRomFsMenu)
|
|
{
|
|
// Reset option to its default value
|
|
selectedAppIndex = (menuType == MENUTYPE_GAMECARD ? 0 : selectedAppInfoIndex);
|
|
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowRomFsSectionDataDumpMenu : resultDumpRomFsSectionData);
|
|
break;
|
|
case 1:
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowRomFsSectionBrowserMenu : resultRomFsSectionBrowserGetEntries);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
if (uiState == stateRomFsSectionBrowser)
|
|
{
|
|
if (menu && menuItemsCount)
|
|
{
|
|
// Save selected file index
|
|
selectedFileIndex = (u32)cursor;
|
|
res = (romFsBrowserEntries[cursor].type == ROMFS_ENTRY_DIR ? resultRomFsSectionBrowserChangeDir : resultRomFsSectionBrowserCopyFile);
|
|
}
|
|
} else
|
|
if (uiState == stateSdCardEmmcMenu)
|
|
{
|
|
// Save selected base application index
|
|
selectedAppInfoIndex = (u32)cursor;
|
|
res = resultShowSdCardEmmcTitleMenu;
|
|
} else
|
|
if (uiState == stateSdCardEmmcTitleMenu)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
if ((!titlePatchCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false)) && (!titleAddOnCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, true)))
|
|
{
|
|
res = resultShowNspAppDumpMenu;
|
|
|
|
// Reset options to their default values
|
|
isFat32 = false;
|
|
calcCrc = false;
|
|
removeConsoleData = false;
|
|
tiklessDump = false;
|
|
selectedAppIndex = selectedAppInfoIndex;
|
|
} else {
|
|
res = resultShowNspDumpMenu;
|
|
}
|
|
break;
|
|
case 1:
|
|
res = resultShowExeFsMenu;
|
|
break;
|
|
case 2:
|
|
res = resultShowRomFsMenu;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
} else
|
|
if (uiState == stateSdCardEmmcOrphanPatchAddOnMenu)
|
|
{
|
|
if (menu && menuItemsCount)
|
|
{
|
|
// Reset options to their default values
|
|
isFat32 = false;
|
|
calcCrc = false;
|
|
removeConsoleData = false;
|
|
tiklessDump = false;
|
|
|
|
if (orphanEntries[cursor].type == ORPHAN_ENTRY_TYPE_PATCH)
|
|
{
|
|
selectedPatchIndex = orphanEntries[cursor].index;
|
|
res = resultShowNspPatchDumpMenu;
|
|
} else
|
|
if (orphanEntries[cursor].type == ORPHAN_ENTRY_TYPE_ADDON)
|
|
{
|
|
selectedAddOnIndex = orphanEntries[cursor].index;
|
|
res = resultShowNspAddOnDumpMenu;
|
|
}
|
|
}
|
|
} else
|
|
if (uiState == stateUpdateMenu)
|
|
{
|
|
switch(cursor)
|
|
{
|
|
case 0:
|
|
res = resultUpdateNSWDBXml;
|
|
break;
|
|
case 1:
|
|
res = resultUpdateApplication;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Back
|
|
if (keysDown & KEY_B)
|
|
{
|
|
if (uiState == stateGameCardMenu || uiState == stateSdCardEmmcMenu || uiState == stateUpdateMenu)
|
|
{
|
|
res = resultShowMainMenu;
|
|
menuType = MENUTYPE_MAIN;
|
|
} else
|
|
if (menuType == MENUTYPE_GAMECARD && (uiState == stateNspDumpMenu || uiState == stateHfs0Menu || uiState == stateExeFsMenu || uiState == stateRomFsMenu))
|
|
{
|
|
res = resultShowGameCardMenu;
|
|
} else
|
|
if (uiState == stateRawHfs0PartitionDumpMenu || uiState == stateHfs0PartitionDataDumpMenu || uiState == stateHfs0BrowserMenu)
|
|
{
|
|
res = resultShowHfs0Menu;
|
|
} else
|
|
if (uiState == stateHfs0Browser)
|
|
{
|
|
free(partitionHfs0Header);
|
|
partitionHfs0Header = NULL;
|
|
partitionHfs0HeaderOffset = 0;
|
|
partitionHfs0HeaderSize = 0;
|
|
partitionHfs0FileCount = 0;
|
|
partitionHfs0StrTableSize = 0;
|
|
|
|
res = resultShowHfs0BrowserMenu;
|
|
} else
|
|
if (uiState == stateExeFsSectionDataDumpMenu || uiState == stateExeFsSectionBrowserMenu)
|
|
{
|
|
res = resultShowExeFsMenu;
|
|
} else
|
|
if (uiState == stateExeFsSectionBrowser)
|
|
{
|
|
freeExeFsContext();
|
|
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowExeFsSectionBrowserMenu : resultShowExeFsMenu);
|
|
} else
|
|
if (uiState == stateRomFsSectionDataDumpMenu || uiState == stateRomFsSectionBrowserMenu)
|
|
{
|
|
res = resultShowRomFsMenu;
|
|
} else
|
|
if (uiState == stateRomFsSectionBrowser)
|
|
{
|
|
if (strlen(curRomFsPath) > 1)
|
|
{
|
|
// Point to the parent directory entry ("..")
|
|
selectedFileIndex = 0;
|
|
res = resultRomFsSectionBrowserChangeDir;
|
|
} else {
|
|
if (romFsBrowserEntries != NULL)
|
|
{
|
|
free(romFsBrowserEntries);
|
|
romFsBrowserEntries = NULL;
|
|
}
|
|
|
|
freeRomFsContext();
|
|
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowRomFsSectionBrowserMenu : resultShowRomFsMenu);
|
|
}
|
|
} else
|
|
if (uiState == stateSdCardEmmcTitleMenu)
|
|
{
|
|
res = resultShowSdCardEmmcMenu;
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC && !orphanMode && (uiState == stateNspDumpMenu || uiState == stateExeFsMenu || uiState == stateRomFsMenu))
|
|
{
|
|
res = resultShowSdCardEmmcTitleMenu;
|
|
} else
|
|
if (uiState == stateSdCardEmmcOrphanPatchAddOnMenu)
|
|
{
|
|
if (orphanEntries != NULL)
|
|
{
|
|
free(orphanEntries);
|
|
orphanEntries = NULL;
|
|
}
|
|
|
|
res = resultShowSdCardEmmcMenu;
|
|
orphanMode = false;
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC && orphanMode && (uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu))
|
|
{
|
|
res = resultShowSdCardEmmcOrphanPatchAddOnMenu;
|
|
}
|
|
}
|
|
|
|
// Dump installed content with missing base application
|
|
if (uiState == stateSdCardEmmcMenu && ((titleAppCount && ((titlePatchCount && checkOrphanPatchOrAddOn(false)) || (titleAddOnCount && checkOrphanPatchOrAddOn(true)))) || (!titleAppCount && (titlePatchCount || titleAddOnCount))) && (keysDown & KEY_Y))
|
|
{
|
|
res = resultShowSdCardEmmcOrphanPatchAddOnMenu;
|
|
orphanMode = true;
|
|
}
|
|
|
|
if (menu && menuItemsCount)
|
|
{
|
|
// Go up
|
|
if ((keysDown & KEY_DUP) || (keysDown & KEY_LSTICK_UP) || (keysHeld & KEY_RSTICK_UP)) scrollAmount = -1;
|
|
if ((keysDown & KEY_DLEFT) || (keysDown & KEY_LSTICK_LEFT) || (keysHeld & KEY_RSTICK_LEFT)) scrollAmount = -5;
|
|
|
|
// Go down
|
|
if ((keysDown & KEY_DDOWN) || (keysDown & KEY_LSTICK_DOWN) || (keysHeld & KEY_RSTICK_DOWN)) scrollAmount = 1;
|
|
if ((keysDown & KEY_DRIGHT) || (keysDown & KEY_LSTICK_RIGHT) || (keysHeld & KEY_RSTICK_RIGHT)) scrollAmount = 5;
|
|
}
|
|
}
|
|
|
|
// Calculate scroll only if the UI state hasn't been changed
|
|
if (res == resultNone)
|
|
{
|
|
if (scrollAmount > 0)
|
|
{
|
|
for(i = 0; i < scrollAmount; i++)
|
|
{
|
|
if (cursor < menuItemsCount - 1)
|
|
{
|
|
cursor++;
|
|
if (((uiState != stateSdCardEmmcMenu && uiState != stateSdCardEmmcOrphanPatchAddOnMenu && uiState != stateHfs0Browser && uiState != stateExeFsSectionBrowser && uiState != stateRomFsSectionBrowser) && (cursor - scroll) >= COMMON_MAX_ELEMENTS) || (uiState == stateSdCardEmmcMenu && (cursor - scroll) >= SDCARD_MAX_ELEMENTS) || (uiState == stateSdCardEmmcOrphanPatchAddOnMenu && (cursor - scroll) >= ORPHAN_MAX_ELEMENTS) || (uiState == stateHfs0Browser && (cursor - scroll) >= HFS0_MAX_ELEMENTS) || ((uiState == stateExeFsSectionBrowser || uiState == stateRomFsSectionBrowser) && (cursor - scroll) >= ROMFS_MAX_ELEMENTS)) scroll++;
|
|
}
|
|
}
|
|
} else
|
|
if (scrollAmount < 0)
|
|
{
|
|
for(i = 0; i < -scrollAmount; i++)
|
|
{
|
|
if (cursor > 0)
|
|
{
|
|
cursor--;
|
|
if ((cursor - scroll) < 0) scroll--;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Avoid placing the cursor on the "Create directory with archive bit set" option in the XCI dump menu if "Split output dump" is disabled
|
|
if (uiState == stateXciDumpMenu && cursor == 2 && !isFat32)
|
|
{
|
|
if (scrollAmount > 0)
|
|
{
|
|
cursor++;
|
|
} else
|
|
if (scrollAmount < 0)
|
|
{
|
|
cursor--;
|
|
}
|
|
}
|
|
|
|
// Avoid placing the cursor on the "Dump bundled update NSP" option in the NSP dump menu if we're dealing with a gamecard and it doesn't include any bundled updates, or if we're dealing with a SD/eMMC title without installed updates
|
|
// Also avoid placing the cursor on the "Dump bundled DLC NSP" option in the NSP dump menu if we're dealing with a gamecard and it doesn't include any bundled DLCs, or if we're dealing with a SD/eMMC title without installed DLCs
|
|
if (uiState == stateNspDumpMenu)
|
|
{
|
|
if (menuType == MENUTYPE_GAMECARD)
|
|
{
|
|
if ((titlePatchCount && !titleAddOnCount) || (!titlePatchCount && titleAddOnCount))
|
|
{
|
|
if (cursor >= 2) cursor = 1;
|
|
} else
|
|
if (!titlePatchCount && !titleAddOnCount)
|
|
{
|
|
// Just in case
|
|
cursor = 0;
|
|
}
|
|
} else
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
if ((titlePatchCount && checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false) && (!titleAddOnCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, true))) || ((!titlePatchCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false)) && titleAddOnCount && checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, true)))
|
|
{
|
|
if (cursor >= 2) cursor = 1;
|
|
} else
|
|
if ((!titlePatchCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, false)) && (!titleAddOnCount || !checkIfBaseApplicationHasPatchOrAddOn(selectedAppInfoIndex, true)))
|
|
{
|
|
// Just in case
|
|
cursor = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Avoid placing the cursor on the "Remove console specific data" and "Generate ticket-less dump" options in the NSP dump menus if we're dealing with a gamecard title
|
|
if (menuType == MENUTYPE_GAMECARD && (uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu) && (cursor == 3 || cursor == 4))
|
|
{
|
|
if (scrollAmount > 0)
|
|
{
|
|
cursor = 5;
|
|
} else
|
|
if (scrollAmount < 0)
|
|
{
|
|
cursor = 2;
|
|
}
|
|
}
|
|
|
|
// Avoid placing the cursor on the "Generate ticket-less dump" option in the NSP dump menus if we're dealing with a SD/eMMC title and the "Remove console specific data" option is disabled
|
|
if (menuType == MENUTYPE_SDCARD_EMMC && (uiState == stateNspAppDumpMenu || uiState == stateNspPatchDumpMenu || uiState == stateNspAddOnDumpMenu) && cursor == 4 && !removeConsoleData)
|
|
{
|
|
if (scrollAmount > 0)
|
|
{
|
|
cursor++;
|
|
} else
|
|
if (scrollAmount < 0)
|
|
{
|
|
cursor--;
|
|
}
|
|
}
|
|
|
|
// Avoid placing the cursor on the parent directory entry ("..") in the RomFS browser if we're currently at the root directory
|
|
if (uiState == stateRomFsSectionBrowser && cursor == 0 && strlen(curRomFsPath) <= 1) cursor = 1;
|
|
}
|
|
}
|
|
} else
|
|
if (uiState == stateDumpXci)
|
|
{
|
|
uiDrawString(gameCardMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", xciDumpMenuItems[1], (isFat32 ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
if (isFat32)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", xciDumpMenuItems[2], (setXciArchiveBit ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
}
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", xciDumpMenuItems[3], (dumpCert ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", xciDumpMenuItems[4], (trimDump ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", xciDumpMenuItems[5], (calcCrc ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpCartridgeImage(isFat32, setXciArchiveBit, dumpCert, trimDump, calcCrc);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowXciDumpMenu;
|
|
} else
|
|
if (uiState == stateDumpNsp)
|
|
{
|
|
uiDrawString((menuType == MENUTYPE_GAMECARD ? nspDumpGameCardMenuItems[selectedNspDumpType] : nspDumpSdCardEmmcMenuItems[selectedNspDumpType]), 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
menu = (selectedNspDumpType == DUMP_APP_NSP ? nspAppDumpMenuItems : (selectedNspDumpType == DUMP_PATCH_NSP ? nspPatchDumpMenuItems : nspAddOnDumpMenuItems));
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", menu[1], (isFat32 ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", menu[2], (calcCrc ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
if (menuType == MENUTYPE_SDCARD_EMMC)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", menu[3], (removeConsoleData ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
if (removeConsoleData)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s", menu[4], (tiklessDump ? "Yes" : "No"));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
}
|
|
}
|
|
|
|
if (selectedNspDumpType == DUMP_APP_NSP)
|
|
{
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", menu[5], titleName[selectedAppIndex], versionStr);
|
|
} else
|
|
if (selectedNspDumpType == DUMP_PATCH_NSP)
|
|
{
|
|
retrieveDescriptionForPatchOrAddOn(titlePatchTitleID[selectedPatchIndex], titlePatchVersion[selectedPatchIndex], false, menu[5]);
|
|
} else
|
|
if (selectedNspDumpType == DUMP_ADDON_NSP)
|
|
{
|
|
retrieveDescriptionForPatchOrAddOn(titleAddOnTitleID[selectedAddOnIndex], titleAddOnVersion[selectedAddOnIndex], true, menu[5]);
|
|
}
|
|
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpNintendoSubmissionPackage(selectedNspDumpType, (selectedNspDumpType == DUMP_APP_NSP ? selectedAppIndex : (selectedNspDumpType == DUMP_PATCH_NSP ? selectedPatchIndex : selectedAddOnIndex)), isFat32, calcCrc, removeConsoleData, tiklessDump);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
|
|
res = (selectedNspDumpType == DUMP_APP_NSP ? resultShowNspAppDumpMenu : (selectedNspDumpType == DUMP_PATCH_NSP ? resultShowNspPatchDumpMenu : resultShowNspAddOnDumpMenu));
|
|
} else
|
|
if (uiState == stateDumpRawHfs0Partition)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Raw %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? hfs0PartitionDumpType1MenuItems[selectedPartitionIndex] : hfs0PartitionDumpType2MenuItems[selectedPartitionIndex]));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpRawHfs0Partition(selectedPartitionIndex, true);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowRawHfs0PartitionDumpMenu;
|
|
} else
|
|
if (uiState == stateDumpHfs0PartitionData)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Data %s", (hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? hfs0PartitionDumpType1MenuItems[selectedPartitionIndex] : hfs0PartitionDumpType2MenuItems[selectedPartitionIndex]));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpHfs0PartitionData(selectedPartitionIndex);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowHfs0PartitionDataDumpMenu;
|
|
} else
|
|
if (uiState == stateHfs0BrowserGetList)
|
|
{
|
|
uiDrawString((hfs0_partition_cnt == GAMECARD_TYPE1_PARTITION_CNT ? hfs0BrowserType1MenuItems[selectedPartitionIndex] : hfs0BrowserType2MenuItems[selectedPartitionIndex]), 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiPleaseWait(0);
|
|
breaks += 2;
|
|
|
|
if (getHfs0FileList(selectedPartitionIndex))
|
|
{
|
|
cursor = 0;
|
|
scroll = 0;
|
|
res = resultShowHfs0Browser;
|
|
} else {
|
|
waitForButtonPress();
|
|
res = resultShowHfs0BrowserMenu;
|
|
}
|
|
} else
|
|
if (uiState == stateHfs0BrowserCopyFile)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Manual File Dump: %s (HFS0 partition %u [%s])", filenames[selectedFileIndex], selectedPartitionIndex, GAMECARD_PARTITION_NAME(hfs0_partition_cnt, selectedPartitionIndex));
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpFileFromHfs0Partition(selectedPartitionIndex, selectedFileIndex, filenames[selectedFileIndex]);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowHfs0Browser;
|
|
} else
|
|
if (uiState == stateDumpExeFsSectionData)
|
|
{
|
|
uiDrawString(exeFsMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", exeFsSectionDumpMenuItems[1], titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpExeFsSectionData(selectedAppIndex, true);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowExeFsSectionDataDumpMenu : resultShowExeFsMenu);
|
|
} else
|
|
if (uiState == stateExeFsSectionBrowserGetList)
|
|
{
|
|
uiDrawString(exeFsMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", exeFsSectionBrowserMenuItems[1], titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiPleaseWait(0);
|
|
breaks += 2;
|
|
|
|
bool exefs_fail = false;
|
|
|
|
if (readProgramNcaExeFsOrRomFs(selectedAppIndex, false))
|
|
{
|
|
if (getExeFsFileList())
|
|
{
|
|
cursor = 0;
|
|
scroll = 0;
|
|
res = resultShowExeFsSectionBrowser;
|
|
} else {
|
|
freeExeFsContext();
|
|
exefs_fail = true;
|
|
}
|
|
} else {
|
|
exefs_fail = true;
|
|
}
|
|
|
|
if (exefs_fail)
|
|
{
|
|
breaks += 2;
|
|
waitForButtonPress();
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowExeFsSectionBrowserMenu : resultShowExeFsMenu);
|
|
}
|
|
} else
|
|
if (uiState == stateExeFsSectionBrowserCopyFile)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Manual File Dump: %s (ExeFS)", filenames[selectedFileIndex]);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Base application: %s v%s", titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpFileFromExeFsSection(selectedAppIndex, selectedFileIndex, true);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowExeFsSectionBrowser;
|
|
} else
|
|
if (uiState == stateDumpRomFsSectionData)
|
|
{
|
|
uiDrawString(romFsMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", romFsSectionDumpMenuItems[1], titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
dumpRomFsSectionData(selectedAppIndex);
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowRomFsSectionDataDumpMenu : resultShowRomFsMenu);
|
|
} else
|
|
if (uiState == stateRomFsSectionBrowserGetEntries)
|
|
{
|
|
uiDrawString(romFsMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", romFsSectionBrowserMenuItems[1], titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiPleaseWait(0);
|
|
breaks += 2;
|
|
|
|
bool romfs_fail = false;
|
|
|
|
if (readProgramNcaExeFsOrRomFs(selectedAppIndex, true))
|
|
{
|
|
if (getRomFsFileList(0))
|
|
{
|
|
cursor = 0;
|
|
scroll = 0;
|
|
res = resultShowRomFsSectionBrowser;
|
|
} else {
|
|
freeRomFsContext();
|
|
romfs_fail = true;
|
|
}
|
|
} else {
|
|
romfs_fail = true;
|
|
}
|
|
|
|
if (romfs_fail)
|
|
{
|
|
breaks += 2;
|
|
waitForButtonPress();
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowRomFsSectionBrowserMenu : resultShowRomFsMenu);
|
|
}
|
|
} else
|
|
if (uiState == stateRomFsSectionBrowserChangeDir)
|
|
{
|
|
uiDrawString(romFsMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "%s%s v%s", romFsSectionBrowserMenuItems[1], titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
bool romfs_fail = false;
|
|
|
|
if (romFsBrowserEntries[selectedFileIndex].type == ROMFS_ENTRY_DIR)
|
|
{
|
|
if (getRomFsFileList(romFsBrowserEntries[selectedFileIndex].offset))
|
|
{
|
|
cursor = 0;
|
|
scroll = 0;
|
|
res = resultShowRomFsSectionBrowser;
|
|
} else {
|
|
romfs_fail = true;
|
|
}
|
|
} else {
|
|
// Unexpected condition
|
|
uiDrawString("Error: the selected entry is not a directory!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
romfs_fail = true;
|
|
}
|
|
|
|
if (romfs_fail)
|
|
{
|
|
if (romFsBrowserEntries != NULL)
|
|
{
|
|
free(romFsBrowserEntries);
|
|
romFsBrowserEntries = NULL;
|
|
}
|
|
|
|
freeRomFsContext();
|
|
|
|
breaks += 2;
|
|
waitForButtonPress();
|
|
res = ((menuType == MENUTYPE_GAMECARD && titleAppCount > 1) ? resultShowRomFsSectionBrowserMenu : resultShowRomFsMenu);
|
|
}
|
|
} else
|
|
if (uiState == stateRomFsSectionBrowserCopyFile)
|
|
{
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Manual File Dump: %s (RomFS)", filenames[selectedFileIndex]);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks++;
|
|
|
|
convertTitleVersionToDecimal(titleAppVersion[selectedAppIndex], versionStr, sizeof(versionStr));
|
|
snprintf(strbuf, sizeof(strbuf) / sizeof(strbuf[0]), "Base application: %s v%s", titleName[selectedAppIndex], versionStr);
|
|
uiDrawString(strbuf, 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
uiRefreshDisplay();
|
|
|
|
if (romFsBrowserEntries[selectedFileIndex].type == ROMFS_ENTRY_FILE)
|
|
{
|
|
dumpFileFromRomFsSection(selectedAppIndex, romFsBrowserEntries[selectedFileIndex].offset, true);
|
|
} else {
|
|
// Unexpected condition
|
|
uiDrawString("Error: the selected entry is not a file!", 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
}
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowRomFsSectionBrowser;
|
|
} else
|
|
if (uiState == stateDumpGameCardCertificate)
|
|
{
|
|
uiDrawString(gameCardMenuItems[4], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
dumpGameCardCertificate();
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowGameCardMenu;
|
|
} else
|
|
if (uiState == stateUpdateNSWDBXml)
|
|
{
|
|
uiDrawString(updateMenuItems[0], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
updateNSWDBXml();
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowUpdateMenu;
|
|
} else
|
|
if (uiState == stateUpdateApplication)
|
|
{
|
|
uiDrawString(updateMenuItems[1], 8, (breaks * (font_height + (font_height / 4))) + (font_height / 8), 115, 115, 255);
|
|
breaks += 2;
|
|
|
|
updateApplication();
|
|
|
|
waitForButtonPress();
|
|
|
|
uiUpdateFreeSpace();
|
|
res = resultShowUpdateMenu;
|
|
}
|
|
|
|
return res;
|
|
}
|