Merge branch 'master' into master

This commit is contained in:
JK 2021-12-02 20:45:45 -05:00 committed by GitHub
commit d1d0564d5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
51 changed files with 2752 additions and 871 deletions

1
.gitignore vendored
View File

@ -1,3 +1,4 @@
build/
.vscode/
*.cbp
*.layout

34
GD_INSTRUCTIONS.MD Normal file
View File

@ -0,0 +1,34 @@
# <center> How to use Google Drive with JKSV </center>
**Google only allows unverified apps to have up to 100 test users. Not only would this limit be filled within minutes, but each user has to manually added. People have been asking for some kind of cloud support since I wrote JKSM on 3DS and this is my way to support it while getting around Google's restrictions.**
1. Go to https://console.cloud.google.com/, if this is your first time, accept the terms and you should now have the dashboard in front of you.
2. Click `CREATE PROJECT` on the next screen.<br><center><img src="https://i.imgur.com/42Wruo4.png" /></center>
3. On the next screen name your project JKSV. Organization is not required. Click create.
4. Give it a few seconds and the project should be created. Select JKSV if it hasn't been selected already.<center><img src="https://i.imgur.com/P1lXGea.png" /></center>
5. On the left side, find APIs and Services and click Dashboard.<br><center><img src="https://i.imgur.com/Ve8NRVr.png" /></center>
6. Once the dashboard loads, click `+ENABLE APIS AND SERVICES`.<br><center><img src="https://i.imgur.com/RzB8ChU.png" /></center>
7. Scroll down a little and find Google Drive API under Google Workspace.<br><center><img src="https://i.imgur.com/cAC7h1r.png" /></center>
8. Click on it and Click Enable on the next screen.
9. On the next screen, Google should be informing you that you need to create credentials in order to use Drive. Click Create Credentials.<br><center><img src="https://i.imgur.com/gMyedT4.png" /></center>
10. Under `Which API are you using?`, find `Cloud Storage API`. Under `What data will you be accessing?`, select `User data`. Click done.
11. On the next screen, there should be a reminder to configure your OAuth Consent screen AKA your login screen. Click `CONFIGURE CONSENT SCREEN`.<br><center><img src="https://i.imgur.com/SGmUnPp.png" /></center>
12. Select external and then create.
13. Fill out the next screen. Only App name, user support email, and developer contact information are required. The rest can be left blank. Save and Continue.
14. On the next screen, click `ADD OR REMOVE SCOPES`. Find `../auth/drive` or just type `https://www.googleapis.com/auth/drive` into `Manually add scopes`. Click update at the bottom. Save and Continue.
15. Add yourself as a test user. Save and Continue.
16. `BACK TO DASHBOARD`
17. On the left under APIs and Services, click Credentials.<br><center><img src="https://i.imgur.com/iWD1GTk.png" /></center>
18. On the next screen, click `+ CREATE_CREDENTIALS`. Select `OAuth Client ID`.<br><center><img src="https://i.imgur.com/ri3tuB7.png" /></center>
19. On the next screen, under `Application Type`, select `Desktop App`. Click `Create`.
20. You now have your Client ID and Client Secret. Copy and paste these somewhere for later. Almost done!
21. You're going to need to login and get an authentication code for JKSV to exchange. This is only needed once. Afterwards, JKSV will use a refresh token so you do not have to log in every time you want to upload or download something. Replace `YOUR_CLIENT_ID_HERE` with your client ID obtained in the previous step: `https://accounts.google.com/o/oauth2/v2/auth?client_id=YOUR_CLIENT_ID_HERE&redirect_uri=urn:ietf:wg:oauth:2.0:oob&response_type=code&scope=https://www.googleapis.com/auth/drive`.
22. At the end, you will be presented with a code. You will need this for the final step.
23. On your Switch's SD card, go to JKSV's config file and open it. `SDMC:/config/JKSV/JKSV.cfg`.
24. Add these lines and save. You should be good to go now:
```
driveClientID = YOUR_CLIENT_ID_HERE
driveClientSecret = YOU_CLIENT_SECRET_HERE
driveAuthCode = YOU_CODE_FROM_STEP_22_HERE
```

View File

@ -38,7 +38,7 @@ INCLUDES := inc inc/ui inc/fs
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK
APP_VERSION := 10.12.2021
APP_VERSION := 11.28.2021
ROMFS := romfs
ICON := icon.jpg

View File

@ -1,54 +1,66 @@
# JKSV
Data Dump/Restore tool for Switch.
JK's Save Manager Switch Edition.
<img src="https://i.imgur.com/yLcTPzt.jpg"/>
## Info
JKSV on Switch started as a small project/port to test some things and get familiar with libnx. A list of what it currently can do:
1. Dump and restore save data.
* This includes the ability to dump and restore to/from any location on SD by pressing minus and using the Advanced Mode.
* Save Data can be dumped and restored directly to and from ZIP archives by enabling `Export To ZIP` in the options menus. Folders will still be detected and usable even with this enabled.
2. Dump system save data
This started as a simple, straight port of my 3DS save manager I publicly released in 2016. Despite not originally wanting to take it too far, I continued working on it for fun when I can. Currently it can:
1. Dump and restore account save data.
2. Dump and restore device saves shared by all users (Games such as Animal Crossing).
3. Dump and restore BCAT Data.
4. Dump and restore cache Saves.
5. Dump system save data.
* Dumping this data is always enabled, but writing back needs to be enabled from the options menu. Writing to this can be very dangerous.
3. Open and explore bis storage partitions via the Extras menu
* Processes can be terminated from the Extras menu allowing you to open even more of these and explore more.
6. Export save data to folders like the orignal or compressed zip files to save space.
7. Create save data so the user no longer needs to boot games to import saves.
* Titles can be rescanned from the Extras menu. For example, if you insert a game card while JKSV is open, rescanning will load and add it to the save creation menu(s).
8. Export and use SVI files to create save data for titles not installed on your system. For games that detect other game saves to unlock content.
* SVI files are simply the title ID, NACP, and icon packed into a file. Placing them in `JKSV/svi` will load them as if they are any other game on your switch. They will appear in the save creation menus with the rest.
9. Extend save data containers to any size the user wants or automatically if the save cannot fit into the current one.
10. Delete save data from the system.
11. Reset save data as if the game was never launched.
12. Display stats and information about the game/save: Play time, launch count, title ID (TID), save ID(SID)/name of save file on user nand partition, etc.
13. Open and explore bis storage partitions via the Extras menu
* BIS Storage is opened inside a basic filebrowser. The partition's listing is on the left. Your SD is on the right.
* Only copying to SD and file properties work on BIS partitions. Writing to and deleting are disabled unless enabled like system save data.
4. Misc Extras:
* Ability to remove downloaded firmware updates from NAND. This is located in the extras menu (ZR on User selection)
14. Misc Extras:
* Ability to remove downloaded firmware updates from NAND. This is located under Extras.
* Terminating processes by [ID](https://switchbrew.org/wiki/Title_list#System_Modules). Allowing you to dump normally unopenable system archives.
* Mount by System Save [ID](https://switchbrew.org/wiki/Flash_Filesystem#System_Savegames). Normally used when the terminated process makes JKSV unable to rescan titles without the Switch crashing.
* Mount and open RomFS of process the homebrew menu takes over (if launched as NRO).
* Hold R while opening a game or applet with Atmosphere so the homebrew menu loads. Open JKSV and press minus and select **Mount Process RomFS**. The romfs of the app should appear in the browser along with your SD on the right.
## Quick Guide
**A custom path can be defined by creating "sdmc:/switch/jksv_dir.txt" and typing the path you want to use. For example, `sdmc:/switch/JKSV/` will force JKSV to create its folder in the switch homebrew folder.**
1. Main/User Menu
* A Selects the currently highlighted user and allows you to browse their titles.
* Y Dumps the save data for all users.
* X opens the sub menu of options for the currently highlighted user:
* Dump All for [X] dumps all of the saves for the highlighted user.
* Create save data opens a list of games found on your switch and will allow to create save data for them without needing to start the games.
* SVI files located in `JKSV/svi` will also be loaded and added to this list. These are to create save data for games not currently on the system. This is for games that search for other saves to unlock extra content.
* Cache saves require a cache index number to be created. This information can be found under information for a cache save when being exported.
* Create All Save Data creates save data for every title on your system for the selected user.
* Delete All Save Data deletes all save data for the selected user. This is permanant.
* Settings and Extras below.
**Custom "safe titles" can be set by creating a file named `titleDefs.txt` in your JKSV directory. These are the folders on SD in which game saves are stored. For example, creating this file and adding the line `0100BFE00E9CA000 = "The Witcher 3 CE"` will set The Witcher 3 to use `[pathto]/JKSV/The Witcher 3 CE/` directory instead of its title id. These need to be ASCII or they will fail to work.**
1. User Select
* A opens the selected user's save files.
* Y Dumps __all__ save data from __all users__, device save data, and BCAT save data. System save data is not included in this.
* X Changes the UI mode to a text menu based one for people that prefer 3DS JKSM style text menus instead.
* Minus Opens the Options menu.
* ZR opens a small menu of extras.
2. Title Select
* A Opens the title for backup and restore.
* L and R change the current user.
* Y Dumps all saves for the currently selected user.
* X adds the selected title to a list of favorites that are pushed to the top of the title list/icons.
* Minus adds the selected title to a list of ignored titles.
* ZR __ERASES__ The selected title's save from the system. This is the same as going into settings and deleting via data management. __THIS DOES NOT DELETE JKSV's SAVE FOLDERS__.
3. Backup/Folder Menu
* Minus opens file mode. File mode is a basic file browser for moving individual files and folders. This also adds the ability to restore saves from any location on your SD card.
* Holding L or R while selecting new with A will automatically name the backup for you without opening the keyboard.
* A creates a new backup
* JKSV adds some suggestions to the keyboard's dictionary such as: date strings, the current user's name **if it's safe**, and the current title or a generated abbreviation.
* Y Restores save data from the selected folder.
* X Deletes the selected folder.
* ZR __ERASES__ the current save data for the title from __your system__, but leaves the archive on NAND.
2. Title/Game Select
* A selects and opens the backup menu.
* Adding `.zip` to the end of your file name will force zip regardless of whether it's enabled or not.
* Y Favorites a title and pushes it to the top of your games.
* L and R jump forward down your games.
* X opens the title options menu:
* Information displays stats about the game for the current user.
* Blacklist adds the title to a list that is not displayed.
* Change Output Folder changes the folder to which the game's saves are written.
* Open in File Mode opens the save in a basic file browser.
* Delete All Save Backups deletes all of the backups for the current title.
* Reset Save Data wipes the save clean as if it was never run.
* Delete Save Data deletes the save data for the title from the system. This is the same as doing it from the Switch's data management setting.
* Extend Save Data extends the container for the current title. This is also done automatically if the save being imported is too large for the container.
* Different games have different limits. Most games do not need this at all. A few will take advantage of a larger container, others extend theirs at times and will need larger containers than created by default.
* Export SVI exports the data needed to create save data for the current title to `JKSV/ncap/[TID].svi`. This is just the title ID, NACP, and icon of the title. These can be used to create save data for games not installed on your system.
4. File Mode
* A opens directories.
@ -60,6 +72,13 @@ JKSV on Switch started as a small project/port to test some things and get famil
* Make Dir creates a folder.
* Properties gets file size and directory size.
* ZL or ZR Change the controlled menu.
5. Settings
* Empty Trash Bin deletes all backups inside the `_TRASH_` folder. The trash bin feature can be disabled further down.
* Check For Updates checks github for updates to JKSV. This currently only updates the NRO release. Maybe NSP later.
* Set JKSV Save Output Folder allows you to set where JKSV's working directory is. Files and folders should be relocated for you.
* Edit Blacklisted Titles allows you to removed titles blacklisted from being shown.
* Delete All Save Backups wipes JKSV's folder of all save backups.
5. Extras
* SD To SD Browser opens the filebrowser with your SD open in both panels
@ -75,7 +94,7 @@ JKSV on Switch started as a small project/port to test some things and get famil
## Building:
1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx)
2. Requires switch-freetype, libpng, zlib, libjpeg-turbo, lib-curl, and lib-json-c
2. `dkp-pacman -S switch-curl switch-freetype switch-libjpeg-turbo switch-libjson-c switch-libpng switch-libwebp switch-sdl2 switch-sdl2_gfx switch-sdl2_image switch-zlib`
## Credits and Thanks:
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8 for loading system font with Freetype. All other font handling code (converting to SDL2, resizing on the fly, checking for glyphs, cache, etc) is my own.

View File

@ -34,4 +34,5 @@ namespace cfg
extern std::vector<uint64_t> blacklist;
extern std::vector<uint64_t> favorites;
extern uint8_t sortType;
extern std::string driveClientID, driveClientSecret, driveRefreshToken, driveAuthCode;
}

View File

@ -1,10 +1,35 @@
#ifndef CURLFUNCS_H
#define CURLFUNCS_H
#pragma once
#include <string>
#include <vector>
std::string getJSONURL(std::vector<std::string> *headers, const std::string& _url);
bool getBinURL(std::vector<uint8_t> *out, const std::string& _url);
#define HEADER_ERROR "ERROR"
#endif // CURLFUNCS_H
namespace curlFuncs
{
typedef struct
{
FILE *f;
uint64_t *o;
} curlUpArgs;
typedef struct
{
std::string path;
unsigned int size;
uint64_t *o;
} curlDlArgs;
size_t writeDataString(const char *buff, size_t sz, size_t cnt, void *u);
size_t writeHeaders(const char *buff, size_t sz, size_t cnt, void *u);
size_t readDataFile(char *buff, size_t sz, size_t cnt, void *u);
size_t readDataBuffer(char *buff, size_t sz, size_t cnt, void *u);
size_t writeDataFile(const char *buff, size_t sz, size_t cnt, void *u);
size_t writeDataBuffer(const char *buff, size_t sz, size_t cnt, void *u);
std::string getHeader(const std::string& _name, std::vector<std::string> *h);
//Shortcuts/legacy
std::string getJSONURL(std::vector<std::string> *headers, const std::string& url);
bool getBinURL(std::vector<uint8_t> *out, const std::string& url);
}

View File

@ -7,14 +7,12 @@
#include "gfx.h"
#define BLD_MON 10
#define BLD_DAY 12
#define BLD_MON 11
#define BLD_DAY 28
#define BLD_YEAR 2021
namespace data
{
extern bool forceMount;
//Loads user + title info
void init();
void exit();
@ -29,7 +27,7 @@ namespace data
{
NacpStruct nacp;
std::string title, safeTitle, author;//Shortcuts sorta.
SDL_Texture *icon;
SDL_Texture *icon = NULL;
bool fav;
} titleInfo;
@ -101,4 +99,4 @@ namespace data
SDL_Texture *getTitleIconByTID(const uint64_t& tid);
int getTitleIndexInUser(const data::user& u, const uint64_t& tid);
extern SetLanguage sysLang;
}
}

View File

@ -8,9 +8,12 @@
#include "fs/dir.h"
#include "fs/zip.h"
#include "fs/fsfile.h"
#include "fs/drive.h"
#include "ui/miscui.h"
#define BUFF_SIZE 0xC0000
#define BUFF_SIZE 0x8000
#define ZIP_BUFF_SIZE 0x10000
#define TRANSFER_BUFFER_LIMIT 0xA00000
namespace fs
{

View File

@ -45,6 +45,7 @@ namespace fs
std::string getItemExt(int index) const { return item[index].getExt(); }
bool isDir(int index) const { return item[index].isDir(); }
unsigned getCount() const { return item.size(); }
fs::dirItem *getDirItemAt(unsigned int _ind) { return &item[_ind]; }
private:
std::string path;

10
inc/fs/drive.h Normal file
View File

@ -0,0 +1,10 @@
#pragma once
#include "../gd.h"
namespace fs
{
extern drive::gd *gDrive;
void driveInit();
void driveExit();
}

View File

@ -1,7 +1,7 @@
#pragma once
#include "data.h"
#include "ui.h"
#include "miscui.h"
#include "type.h"
namespace fs

70
inc/gd.h Normal file
View File

@ -0,0 +1,70 @@
#pragma once
#include <curl/curl.h>
#include <json-c/json.h>
#include <string>
#include <vector>
#include <unordered_map>
#include "curlfuncs.h"
#define HEADER_CONTENT_TYPE_APP_JSON "Content-Type: application/json; charset=UTF-8"
#define HEADER_AUTHORIZATION "Authorization: Bearer "
#define MIMETYPE_FOLDER "application/vnd.google-apps.folder"
namespace drive
{
typedef struct
{
std::string name, id, mimeType;
unsigned int size;
std::vector<std::string> parents;
} gdDirItem;
class gd
{
public:
gd(const std::string& _clientID, const std::string& _secretID, const std::string& _authCode, const std::string& _rToken);
void exhangeAuthCode(const std::string& _authCode);
bool hasToken() { return token.empty() == false; }
void refreshToken();
bool tokenIsValid();
//Drive query parameters are appened to the default
void loadDriveList(const std::string& _qParams);
void debugWriteList();
bool createDir(const std::string& _dirName);
bool dirExists(const std::string& _dirName);
void setRootDir(const std::string& _dirID)
{
rootDir = _dirID;
parentDir = _dirID;
loadDriveList("");
}
void returnToRoot(){ parentDir = rootDir; loadDriveList(""); }
void chDir(const std::string& _dirID) { parentDir = _dirID; loadDriveList(""); }
bool fileExists(const std::string& _filename);
void uploadFile(const std::string& _filename, curlFuncs::curlUpArgs *_upload);
void updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload);
void downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download);
void deleteFile(const std::string& _fileID);
std::string getClientID() const { return clientID; }
std::string getClientSecret() const { return secretID; }
std::string getRefreshToken() const { return rToken; }
std::string getFileID(const std::string& name);
size_t getDriveListCount() const { return driveList.size(); }
drive::gdDirItem *getDirItemAt(unsigned int _ind) { return &driveList[_ind]; }
private:
std::vector<gdDirItem> driveList;
std::string clientID, secretID, token, rToken;
std::string rootDir = "", parentDir = "";
};
}

View File

@ -15,6 +15,7 @@
#include "ui/sldpanel.h"
#include "ui/usr.h"
#include "ui/ttl.h"
#include "ui/fld.h"
#include "ui/sett.h"
#include "ui/ext.h"
#include "ui/fm.h"

19
inc/ui/fld.h Normal file
View File

@ -0,0 +1,19 @@
#pragma once
#include "ui.h"
#include "dir.h"
namespace ui
{
//extern ui::menu *fldMenu;
extern ui::slideOutPanel *fldPanel;
//extern fs::dirList *fldList;
void fldInit();
void fldExit();
void fldUpdate();
//Populate to open menu, refresh for updating after actions
void fldPopulateMenu();
void fldRefreshMenu(bool _updateDrive);
}

View File

@ -4,7 +4,7 @@ namespace ui
{
void fmInit();
void fmExit();
void fmPrep(const FsSaveDataType& _type, const std::string& _dev, bool _commit);
void fmPrep(const FsSaveDataType& _type, const std::string& _dev, const std::string& _baseSDMC, bool _commit);
void fmUpdate();
void fmDraw(SDL_Texture *target);
}

View File

@ -4,9 +4,8 @@ namespace ui
{
void ttlInit();
void ttlExit();
void ttlSetActive(int usr);
void ttlSetActive(int usr, bool _set, bool _showSel);
void ttlRefresh();
void populateFldMenu();
//JIC for func ptr
void ttlReset();

View File

@ -1,5 +1,4 @@
#ifndef UTIL_H
#define UTIL_H
#pragma once
#include "data.h"
#include "ui.h"
@ -37,6 +36,37 @@ namespace util
CPU_SPEED_1785MHz = 1785000000
} cpuSpds;
typedef enum
{
GPU_SPEED_0MHz = 0,
GPU_SPEED_76MHz = 76800000,
GPU_SPEED_153MHz = 153600000,
GPU_SPEED_203MHz = 230400000,
GPU_SPEED_307MHz = 307200000, //Handheld 1
GPU_SPEED_384MHz = 384000000, //Handheld 2
GPU_SPEED_460MHz = 460800000,
GPU_SPEED_537MHz = 537600000,
GPU_SPEED_614MHz = 614400000,
GPU_SPEED_768MHz = 768000000, //Docked
GPU_SPEED_844MHz = 844800000,
GPU_SPEED_921MHZ = 921600000
} gpuSpds;
typedef enum
{
RAM_SPEED_0MHz = 0,
RAM_SPEED_40MHz = 40800000,
RAM_SPEED_68MHz = 68000000,
RAM_SPEED_102MHz = 102000000,
RAM_SPEED_204MHz = 204000000,
RAM_SPEED_408MHz = 408000000,
RAM_SPEED_665MHz = 665600000,
RAM_SPEED_800MHz = 800000000,
RAM_SPEED_1065MHz = 1065600000,
RAM_SPEED_1331MHz = 1331200000,
RAM_SPEED_1600MHz = 1600000000
} ramSpds;
//Returns string with date S+ time
std::string getDateTime(int fmt);
@ -112,7 +142,8 @@ namespace util
Result accountDeleteUser(AccountUid *uid);
void setCPU(uint32_t hz);
void sysBoost();
void sysNormal();
void checkForUpdate(void *a);
}
#endif // UTIL_H

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "Save Index: "
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "System Save\n"
saveDataTypeText = 1, "Save Data\n"
saveDataTypeText = 2, "BCAT\n"
saveDataTypeText = 3, "Device Save\n"
saveDataTypeText = 4, "Temp Storage\n"
saveDataTypeText = 5, "Cache Storage\n"
saveDataTypeText = 6, "System BCAT\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "存檔索引號:"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "系統存檔\n"
saveDataTypeText = 1, "用戶存檔\n"
saveDataTypeText = 2, "BCAT存檔\n"
saveDataTypeText = 3, "設備存檔\n"
saveDataTypeText = 4, "臨時存檔\n"
saveDataTypeText = 5, "緩存存檔\n"
saveDataTypeText = 6, "系統BCAT存檔\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -34,26 +40,23 @@ fileModeMenu = 4, "Properties"
fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Folder"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "Save Index: "
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "System Save\n"
saveDataTypeText = 1, "Save Data\n"
saveDataTypeText = 2, "BCAT\n"
saveDataTypeText = 3, "Device Save\n"
saveDataTypeText = 4, "Temp Storage\n"
saveDataTypeText = 5, "Cache Storage\n"
saveDataTypeText = 6, "System BCAT\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -1,156 +1,213 @@
author = 0, "NULL"
confirmBlacklist = 0, "Are you sure you want to add #%s# to your blacklist?"
confirmCopy = 0, "Are you sure you want to copy #%s# to #%s#?"
confirmCreateAllSaveData = 0, "Are you sure you would like to create all save data on this system for #%s#? This can take a while depending on how many titles are found."
confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
confirmBlacklist = 0, "¿Estás seguro que deseas adicionar #%s# a la lista negra?"
confirmCopy = 0, "¿Seguro que desea copiar #%s# a #%s#?"
confirmCreateAllSaveData = 0, "¿Seguro que desea crear respaldo de todas las partidas guardadas en el sistema para #%s#? ¡Puede tomar un tiempo dependiendo de la cantidad de títulos!"
confirmDelete = 0, "¿Seguro que desea borrar #%s#? *¡Es permanente!*"
confirmDeleteBackupsAll = 0, "¿Seguro que desea borrar *TODOS* los respaldos de partidas guardadas para todos sus juegos?"
confirmDeleteBackupsTitle = 0, "¿Seguro que desea borrar todos los respaldos de partidas guardadas para #%s#?"
confirmDeleteSaveData = 0, "*ADVERTENCIA*: Ésto eliminará la partida guardada para #%s# *DE SU SISTEMA*. ¿Está seguro que así lo desea?"
#CHANGED=============================================>
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
#<====================================================
confirmOverwrite = 0, "¿Sobre escribir #%s#?"
confirmResetSaveData = 0, "*ADVERTENCIA*: Ésto restablecerá la partida guardada para este juego, como si nunca se hubiera ejecutado. ¿Está seguro que es lo que desea?"
confirmRestore = 0, "¿Seguro que desea restaurar #%s#?"
#CHANGED=============================================>
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
#<====================================================
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
extrasMenu = 0, "SD to SD Browser"
dialogYes = 0, "Si [A]"
extrasMenu = 0, "Navegador de SD a SD"
extrasMenu = 1, "BIS: ProdInfoF"
extrasMenu = 2, "BIS: Safe"
extrasMenu = 3, "BIS: System"
extrasMenu = 4, "BIS: User"
extrasMenu = 5, "Remove Pending Update"
extrasMenu = 6, "Terminate Process"
extrasMenu = 7, "Mount System Save"
extrasMenu = 8, "Rescan Titles"
extrasMenu = 9, "Mount Process RomFS"
extrasMenu = 10, "Backup JKSV Folder"
extrasMenu = 5, "Eliminar actualizaciones pendientes"
extrasMenu = 6, "Detener proceso"
extrasMenu = 7, "Montar 'System Save'"
extrasMenu = 8, "Recargar Lista de Títulos"
extrasMenu = 9, "Montar 'Process RomFS'"
extrasMenu = 10, "Realizar respaldo de la carpeta de JKSV"
extrasMenu = 11, "*[DEV]* Output en-US"
fileModeFileProperties = 0, "Path: %s\nSize: %s"
fileModeFolderProperties = 0, "Path: %s\nSub Folders: %u\nFile Count: %u\nTotal Size: %s"
fileModeMenu = 0, "Copy To "
fileModeMenu = 1, "Delete"
fileModeMenu = 2, "Rename"
fileModeMenu = 3, "Make Dir"
fileModeMenu = 4, "Properties"
fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
loadingStartPage = 0, "Loading..."
fileModeFileProperties = 0, "Ruta: %s\nTamaño: %s"
fileModeFolderProperties = 0, "Ruta: %s\nSubCarpetas: %u\nCantidad Archivos: %u\nTamaño Total: %s"
fileModeMenu = 0, "Copiar a "
fileModeMenu = 1, "Borrar"
fileModeMenu = 2, "Renombrar"
fileModeMenu = 3, "Crear Carpeta"
fileModeMenu = 4, "Propiedades"
fileModeMenu = 5, "Cerrar"
fileModeMenu = 6, "Adicionar a filtros de Carpetas"
fileModeMenuMkDir = 0, "Nuevo"
folderMenuNew = 0, "Nuevo Respaldo"
#CHANGED=============================================>
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
#<====================================================
helpSettings = 0, "[A] Alternar [X] Predeterminados [B] Atrás"
helpTitle = 0, "[A] Seleccionar [L][R] Saltar [Y] Favoritos [X] Opciones de Títulos [B] Atrás"
helpUser = 0, "[A] Seleccionar [X] Opciones de Usuario"
holdingText = 0, "(Sostenga) "
holdingText = 1, "(Siga Sosteniendo) "
holdingText = 2, "(¡Ya Casi!) "
#CHANGED=============================================>
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
#<=====================================================
loadingStartPage = 0, "Cargando..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
onlineErrorConnecting = 0, "Error Connecting!"
onlineNoUpdates = 0, "No Updates Available."
popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSaveIsEmpty = 0, "Save data is empty!"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
saveDataCreatedForUser = 0, "Save data created for %s!"
saveDataCreationFailed = 0, "Save data creation failed!"
saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %s?*"
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "存檔索引號:"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "系統存檔\n"
saveDataTypeText = 1, "用戶存檔\n"
saveDataTypeText = 2, "BCAT存檔\n"
saveDataTypeText = 3, "設備存檔\n"
saveDataTypeText = 4, "臨時存檔\n"
saveDataTypeText = 5, "緩存存檔\n"
saveDataTypeText = 6, "系統BCAT存檔\n"
saveTypeMainMenu = 0, "Device"
mainMenuSettings = 0, "Configuraciones"
onlineErrorConnecting = 0, "¡Error Conectando!"
onlineNoUpdates = 0, "No hay actualizaciones disponibles."
popAddedToPathFilter = 0, "se adicionó '#%s#' a filtros de carpeta."
popCPUBoostEnabled = 0, "Aumento de CPU para ZIP."
popChangeOutputError = 0, "#%s# contiene carácteres ilegales o no-ASCII."
popChangeOutputFolder = 0, "Se cambia #%s# por #%s#"
#CHANGED=============================================>
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
#<====================================================
popErrorCommittingFile = 0, "¡Error guardando archivo!"
popFolderIsEmpty = 0, "¡La carpeta está vacía!"
popProcessShutdown = 0, "#%s# Apagado satisfactorio."
#CHANGED=============================================>
popSVIExported = 0, "SVI Exported."
#<====================================================
popSaveIsEmpty = 0, "¡Partida Guardada está vacía!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "¡Archivo ZIP está vacío!"
saveDataBackupDeleted = 0, "#%s# ha sido borrado."
saveDataBackupMovedToTrash = 0, "#%s# ha sido movido a papelera."
saveDataCreatedForUser = 0, "Se creó Partida Guardada para %s!"
saveDataCreationFailed = 0, "¡Error en creación de Partida Guardada!"
saveDataDeleteAllUser = 0, "*¿SEGURO QUE DESEA BORRAR TODAS LAS PARTIDAS GUARDADAS DE %s?*"
saveDataDeleteSuccess = 0, "¡Se borró la Partida Guardada de #%s#!"
saveDataExtendFailed = 0, "Error al expandir la partida guardada."
saveDataExtendSuccess = 0, "¡Partida Guardada para #%s# epandida con éxito!"
saveDataIndexText = 0, "Guardar Índice: "
saveDataNoneFound = 0, "¡No se encontraron partidas guardadas para #%s#!"
saveDataResetSuccess = 0, "¡Partida Guardada para #%s# restablecida!"
saveDataTypeText = 0, "Datos de Sistema"
saveDataTypeText = 1, "Partida Guardada"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Datos de Dispositivo"
saveDataTypeText = 4, "Almacenamiento Temporal"
saveDataTypeText = 5, "Almacenamiento de Caché"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Dispositivo"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
saveTypeMainMenu = 2, "Caché"
saveTypeMainMenu = 3, "Sistema"
saveTypeMainMenu = 4, "BCAT de Sistema"
saveTypeMainMenu = 5, "SysTemp Storagetem"
settingsMenu = 0, "Empty Trash Bin"
settingsMenu = 1, "Check for Updates"
settingsMenu = 2, "Set JKSV Save Output Folder"
settingsMenu = 3, "Edit Blacklisted Titles"
settingsMenu = 4, "Delete All Save Backups"
settingsMenu = 5, "Include Device Saves With Users: "
settingsMenu = 6, "Auto Backup On Restore: "
settingsMenu = 7, "Auto-Name Backups: "
settingsMenu = 8, "Overclock/CPU Boost: "
settingsMenu = 9, "Hold To Delete: "
settingsMenu = 10, "Hold To Restore: "
settingsMenu = 11, "Hold To Overwrite: "
settingsMenu = 12, "Force Mount: "
settingsMenu = 13, "Account System Saves: "
settingsMenu = 14, "Enable Writing to System Saves: "
settingsMenu = 15, "Use FS Commands Directly: "
settingsMenu = 16, "Export Saves to ZIP: "
settingsMenu = 17, "Force English To Be Used: "
settingsMenu = 18, "Enable Trash Bin: "
settingsMenu = 19, "Title Sorting Type: "
settingsMenu = 20, "Animation Scale: "
settingsOff = 0, "Off"
settingsOn = 0, ">On>"
sortType = 0, "Alphabetical"
sortType = 1, "Time Played"
sortType = 2, "Last Played"
swkbdEnterName = 0, "Enter a new name"
swkbdExpandSize = 0, "Enter New Size in MB"
swkbdMkDir = 0, "Enter a folder name"
swkbdNewSafeTitle = 0, "Input New Output Folder"
swkbdProcessID = 0, "Enter Process ID"
swkbdRename = 0, "Enter a new name for item"
swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
titleOptions = 3, "Open in File Mode"
titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"
userOptions = 2, "Create All Save Data"
userOptions = 3, "Delete All User Saves"
settingsMenu = 0, "Vaciar Papelera"
settingsMenu = 1, "Buscar Actualizaciones"
settingsMenu = 2, "Configurar carpeta de salida para JKSV"
settingsMenu = 3, "Editar lista negra de Títulos"
settingsMenu = 4, "Eliminar todos los respaldos"
settingsMenu = 5, "Incluír Datos de Dispositivo con los Usuarios: "
settingsMenu = 6, "Crear respaldo automático al restaurar: "
settingsMenu = 7, "Nombrar Automáticamente los respaldos: "
settingsMenu = 8, "Overclock/Aumento de CPU: "
settingsMenu = 9, "Sostener para Borrar: "
settingsMenu = 10, "Sostener para Restaurar: "
settingsMenu = 11, "Sostener para Sobreescribir: "
settingsMenu = 12, "Montar forzado: "
settingsMenu = 13, "Datos de la cuenta de Sistema: "
settingsMenu = 14, "Habilitar escritura para datos de Sistema: "
settingsMenu = 15, "Usar comandos FS directamente: "
settingsMenu = 16, "Exportar partidas guardadas a archivos ZIP: "
settingsMenu = 17, "Forzar el uso de Inglés: "
settingsMenu = 18, "Habilitar papelera: "
settingsMenu = 19, "Ordenar por : "
settingsMenu = 20, "Escala de Animación: "
settingsOff = 0, "Apagado"
settingsOn = 0, ">Encendido>"
sortType = 0, "Alfabetico"
sortType = 1, "Duración Juegos"
sortType = 2, "Último Jugado"
swkbdEnterName = 0, "Ingrese un nuevo nombre"
swkbdExpandSize = 0, "Ingrese nuevo tamaño en MB"
swkbdMkDir = 0, "Ingrese nombre de carpeta"
swkbdNewSafeTitle = 0, "Ingrese Nueva Carpeta de Salida"
swkbdProcessID = 0, "Ingrese ID de proceso"
swkbdRename = 0, "Ingrese un nuevo nombre para el elemento"
swkbdSaveIndex = 0, "Ingrese Índice de Caché"
swkbdSetWorkDir = 0, "Ingrese Nueva Carpeta de Salida"
swkbdSysSavID = 0, "Ingrese ID de Datos de Sistema"
threadStatusAddingFileToZip = 0, "Agregando '#%s#' a archivo ZIP..."
#CHANGED=============================================>
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
#<====================================================
threadStatusCheckingForUpdate = 0, "Verificando actualizaciones..."
#CHANGED=============================================>
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
#<====================================================
threadStatusCopyingFile = 0, "Copiando '#%s#'..."
threadStatusCreatingSaveData = 0, "Creando Partida Guardada para #%s#..."
threadStatusDecompressingFile = 0, "Descomprimiendo '#%s#'..."
threadStatusDeletingFile = 0, "Borrando..."
threadStatusDeletingSaveData = 0, "Borrando Partida Guardada para #%s#..."
threadStatusDeletingUpdate = 0, "Borrando Actualización Pendiente..."
#CHANGED=============================================>
threadStatusDownloadingFile = 0, "Downloading #%s#..."
#<====================================================
threadStatusDownloadingUpdate = 0, "Borrando Actualización..."
threadStatusExtendingSaveData = 0, "Expandiendo Datos Guardados para #%s#..."
threadStatusGetDirProps = 0, "Obteniendo propiedades de Carpeta..."
threadStatusOpeningFolder = 0, "Abriendo '#%s#'..."
threadStatusPackingJKSV = 0, "Guardando contenidos de carpeta de JKSV en archivo ZIP..."
threadStatusResettingSaveData = 0, "Restableciendo datos de partida..."
threadStatusSavingTranslations = 0, "Saving the file master..."
#CHANGED=============================================>
threadStatusUploadingFile = 0, "Uploading #%s#..."
#<====================================================
titleOptions = 0, "Información"
titleOptions = 1, "Lista Negra"
titleOptions = 2, "Cambiar Carpeta de Salida"
titleOptions = 3, "Abrir en Modo Archivo"
titleOptions = 4, "Borrar todos los respaldos"
titleOptions = 5, "Restablecer Datos de Partida"
titleOptions = 6, "Borrar Datos de Partida"
titleOptions = 7, "Expandir Datos de Partida"
#CHANGED=============================================>
titleOptions = 8, "Export SVI"
#<====================================================
translationMainPage = 0, "Traducción: "
userOptions = 0, "Extrar Todo para "
userOptions = 1, "Crear Datos de Partida"
userOptions = 2, "Crear Todos los Datos de Partida"
userOptions = 3, "Borrar Datos de Partida para todos los Usuarios"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "Save Index: "
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "System Save\n"
saveDataTypeText = 1, "Save Data\n"
saveDataTypeText = 2, "BCAT\n"
saveDataTypeText = 3, "Device Save\n"
saveDataTypeText = 4, "Temp Storage\n"
saveDataTypeText = 5, "Cache Storage\n"
saveDataTypeText = 6, "System BCAT\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "存檔索引號:"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "系統存檔\n"
saveDataTypeText = 1, "用戶存檔\n"
saveDataTypeText = 2, "BCAT存檔\n"
saveDataTypeText = 3, "設備存檔\n"
saveDataTypeText = 4, "臨時存檔\n"
saveDataTypeText = 5, "緩存存檔\n"
saveDataTypeText = 6, "系統BCAT存檔\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,23 @@ confirmDelete = 0, "Souhaitez-vous vraiment supprimer #%s# ? *Ceci sera permane
confirmDeleteBackupsAll = 0, "Êtes-vous sûr de vouloir supprimer *toutes* vos sauvegardes pour tous vos jeux ?"
confirmDeleteBackupsTitle = 0, "Souhaitez-vous vraiment supprimer toutes les sauvegardes sauvegardées pour #%s#?"
confirmDeleteSaveData = 0, "*ATTENTION* : Ceci *effacera* les données sauvegardées pour #%s# *de votre système*. Êtes-vous sûr de vouloir faire cela ?"
#CHANGED=============================================>
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
#<====================================================
confirmOverwrite = 0, "Souhaitez-vous vraiment écraser #%s#?"
confirmResetSaveData = 0, "*ATTENTION* : Cela *réinitialisera* les données de sauvegarde de ce jeu comme s'il n'avait jamais été exécuté auparavant. Êtes-vous sûr de vouloir faire cela ?"
confirmRestore = 0, "Souhaitez-vous vraiment restaurer #%s#?"
#CHANGED=============================================>
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
#<====================================================
dialogNo = 0, "Non [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Oui [A]"
@ -35,25 +49,29 @@ fileModeMenu = 5, "Fermer"
fileModeMenu = 6, "Ajouter aux filtres de chemins"
fileModeMenuMkDir = 0, "Nouveau"
folderMenuNew = 0, "Nouvelle sauvegarde"
helpFolder = 0, "[A] Sélectionner [Y] Restaurer [X] Supprimer [B] Fermer"
#CHANGED=============================================>
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
#<====================================================
helpSettings = 0, "[A] Basculer [X] Défauts [B] Retour"
helpTitle = 0, "[A] Sélectionner [L][R] Saut de page [Y] Favorie [X] Options du titre [B] Retour"
helpUser = 0, "[A] Sélectionner [X] Options pour l'utilisateur"
holdingText = 0, "(Maintenir) "
holdingText = 1, "(Garder maintenu) "
holdingText = 2, "(Presque fini!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Temps de jeu: "
infoStatus = 3, "Lancements au total: "
infoStatus = 4, "Nombre d'utilisateur: "
infoStatus = 5, "Utilisateur actuel: "
infoStatus = 6, "Titre actuel: "
infoStatus = 7, "Titre saufs: "
infoStatus = 8, "Type de tri: "
infoStatus = 9, "Sauvegarde du fichier principal..."
infoStatus = 10, "Supression..."
infoStatus = 11, "Corbeille vidée."
#CHANGED=============================================>
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
#<=====================================================
loadingStartPage = 0, "Chargement..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Paramètres"
@ -63,10 +81,23 @@ popAddedToPathFilter = 0, "'#%s#' ajouté aux filtres de chemins."
popCPUBoostEnabled = 0, "CPU Boost activé pour les ZIP."
popChangeOutputError = 0, "#%s# contient des caractères incorrects ou non-ASCII."
popChangeOutputFolder = 0, "#%s# modifié en #%s#"
#CHANGED=============================================>
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
#<====================================================
popErrorCommittingFile = 0, "Erreur d'ajout du fichier à la sauvegarde!"
popFolderIsEmpty = 0, "Le dossier est vide!"
popProcessShutdown = 0, "#%s# terminé avec succès."
#CHANGED=============================================>
popSVIExported = 0, "SVI Exported."
#<====================================================
popSaveIsEmpty = 0, "Les données de la sauvegarde sont vides!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "Le fichier ZIP est vide!"
saveDataBackupDeleted = 0, "#%s# a été supprimé."
saveDataBackupMovedToTrash = 0, "#%s# a été déplacé dans la corbeille."
@ -79,13 +110,13 @@ saveDataExtendSuccess = 0, "Données de la sauvegarde pour #%s# étendue!"
saveDataIndexText = 0, "Index de la sauvegarde: "
saveDataNoneFound = 0, "Aucune sauvegarde trouvée pour #%s#!"
saveDataResetSuccess = 0, "Sauvegarde pour #%s# réinitialisée!"
saveDataTypeText = 0, "Sauvegarde système\n"
saveDataTypeText = 1, "Données de sauvegarde\n"
saveDataTypeText = 2, "BCAT\n"
saveDataTypeText = 3, "Sauvegarde de périphérique\n"
saveDataTypeText = 4, "Stockage temporaire\n"
saveDataTypeText = 5, "Stockage cache\n"
saveDataTypeText = 6, "BCAT système\n"
saveDataTypeText = 0, "Sauvegarde système"
saveDataTypeText = 1, "Données de sauvegarde"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Sauvegarde de périphérique"
saveDataTypeText = 4, "Stockage temporaire"
saveDataTypeText = 5, "Stockage cache"
saveDataTypeText = 6, "BCAT système"
saveTypeMainMenu = 0, "Périphérique"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +159,40 @@ swkbdSaveIndex = 0, "Entrez l'index du cache"
swkbdSetWorkDir = 0, "Entrez un nouveau chemin de sortie"
swkbdSysSavID = 0, "Entrez l'ID de la sauvegarde système"
threadStatusAddingFileToZip = 0, "Ajout de '#%s#' au ZIP..."
#CHANGED=============================================>
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
#<====================================================
threadStatusCheckingForUpdate = 0, "Vérification de mises à jour..."
#CHANGED=============================================>
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
#<====================================================
threadStatusCopyingFile = 0, "Copie de '#%s#'..."
threadStatusCreatingSaveData = 0, "Création de la sauvegarde pour #%s#..."
threadStatusDecompressingFile = 0, "Décompression de '#%s#'..."
threadStatusDeletingFile = 0, "Suppression..."
threadStatusDeletingSaveData = 0, "Supression de la sauvegarde pour #%s#..."
threadStatusDeletingUpdate = 0, "Suppression de la mise à jour en attente..."
#CHANGED=============================================>
threadStatusDownloadingFile = 0, "Downloading #%s#..."
#<====================================================
threadStatusDownloadingUpdate = 0, "Téléchargement de la mise à jour..."
threadStatusExtendingSaveData = 0, "Extention de la sauvegarde pour #%s#..."
threadStatusGetDirProps = 0, "Obtention des propriétés du dossier..."
threadStatusOpeningFolder = 0, "Ouverture de '#%s#'..."
threadStatusPackingJKSV = 0, "Ecriture du contenu du répertoire JKSV dans le ZIP..."
threadStatusResettingSaveData = 0, "Réinitialisation de la sauvegarde..."
threadStatusSavingTranslations = 0, "Saving the file master..."
#CHANGED=============================================>
threadStatusUploadingFile = 0, "Uploading #%s#..."
#<====================================================
titleOptions = 0, "Information"
titleOptions = 1, "Liste noir"
titleOptions = 2, "Changer le dossier de sortie"
@ -149,6 +201,11 @@ titleOptions = 4, "Supprimer toutes les sauvegardes de la sauvegarde"
titleOptions = 5, "Réinitialiser la sauvegarde"
titleOptions = 6, "Supprimer la sauvegarde"
titleOptions = 7, "Etendre la sauvegarde"
#CHANGED=============================================>
titleOptions = 8, "Export SVI"
#<====================================================
translationMainPage = 0, "Traduction: "
userOptions = 0, "Dumper tout pour"
userOptions = 1, "Sauvegarder la sauvegarde"

View File

@ -79,13 +79,13 @@ saveDataExtendSuccess = 0, "Salvataggio di #%s# esteso!"
saveDataIndexText = 0, "Indice Salvataggio: "
saveDataNoneFound = 0, "Nessun Salvataggio trovato per #%s#!"
saveDataResetSuccess = 0, "Salvataggio di #%s# resettato!"
saveDataTypeText = 0, "Salvataggi Sistema\n"
saveDataTypeText = 1, "Save Data\n"
saveDataTypeText = 2, "BCAT\n"
saveDataTypeText = 3, "Salvataggi Dispositivo\n"
saveDataTypeText = 4, "Memoria Temporanea\n"
saveDataTypeText = 5, "Memoria Cache\n"
saveDataTypeText = 6, "System BCAT\n"
saveDataTypeText = 0, "Salvataggi Sistema"
saveDataTypeText = 1, "Save Data"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Salvataggi Dispositivo"
saveDataTypeText = 4, "Memoria Temporanea"
saveDataTypeText = 5, "Memoria Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Dispositivo"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"

View File

@ -6,9 +6,23 @@ confirmDelete = 0, "#%s#を削除してもよろしいですか? これは永続
confirmDeleteBackupsAll = 0, "全てのゲームのセーブバックアップを全て削除してもよろしいですか?"
confirmDeleteBackupsTitle = 0, "#%s#のすべてのセーブデータのバックアップを削除してもよろしいですか?"
confirmDeleteSaveData = 0, "警告: これにより、#%s#のセーブデータがシステムから消去されます。 これを実行してもよろしいですか?"
#CHANGED=============================================>
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
#<====================================================
confirmOverwrite = 0, "#%s#を上書きしてもよろしいですか?"
confirmResetSaveData = 0, "警告: これにより、このゲームのセーブデータが、以前に実行されたことがないかのようにリセットされます。これを実行してもよろしいですか?"
confirmRestore = 0, "#%s#を復元してもよろしいですか?"
#CHANGED=============================================>
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
#<====================================================
dialogNo = 0, "いいえ [B]"
dialogOK = 0, "了解 [A]"
dialogYes = 0, "はい [A]"
@ -35,25 +49,29 @@ fileModeMenu = 5, "閉じる"
fileModeMenu = 6, "パスフィルターに追加"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] 選択 [Y] リストア [X] 削除 [B] 閉じる"
#CHANGED=============================================>
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
#<====================================================
helpSettings = 0, "[A] トグル [X] デフォルト [B] 戻る"
helpTitle = 0, "[A] 選択 [L][R] ジャンプ [Y] お気に入り [X] タイトルオプション [B] 戻る"
helpUser = 0, "[A] 選択 [X] ユーザー設定"
holdingText = 0, "(所有) "
holdingText = 1, "(保持し続けます) "
holdingText = 2, "(もうすぐです!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
#CHANGED=============================================>
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
#<=====================================================
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +81,23 @@ popAddedToPathFilter = 0, "'#%s#' パスフィルターに追加されました
popCPUBoostEnabled = 0, "ZIPでCPUブーストが有効になっています。"
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
#CHANGED=============================================>
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
#<====================================================
popErrorCommittingFile = 0, "保存するファイルのコミット中にエラーが発生しました!"
popFolderIsEmpty = 0, "フォルダは空です!"
popProcessShutdown = 0, "#%s# 正常にシャットダウンしました。"
#CHANGED=============================================>
popSVIExported = 0, "SVI Exported."
#<====================================================
popSaveIsEmpty = 0, "セーブデータは空です!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIPファイルは空です!"
saveDataBackupDeleted = 0, "#%s#が削除されました。"
saveDataBackupMovedToTrash = 0, "#%s#はゴミ箱に移動されました"
@ -128,19 +159,40 @@ swkbdSaveIndex = 0, "キャッシュインデックスを入力してくださ
swkbdSetWorkDir = 0, "新しい出力パスを入力してください"
swkbdSysSavID = 0, "システムセーブIDを入力してください"
threadStatusAddingFileToZip = 0, "#%s#をZIPに追加中..."
#CHANGED=============================================>
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
#<====================================================
threadStatusCheckingForUpdate = 0, "アップデートの確認中..."
#CHANGED=============================================>
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
#<====================================================
threadStatusCopyingFile = 0, "#%s#をコピーしています..."
threadStatusCreatingSaveData = 0, "#%s#のセームデータの作成中..."
threadStatusDecompressingFile = 0, "#%s#の解凍中..."
threadStatusDeletingFile = 0, "削除中..."
threadStatusDeletingSaveData = 0, "#%s#のセーブデータを削除中..."
threadStatusDeletingUpdate = 0, "保留中のアップデータを削除中..."
#CHANGED=============================================>
threadStatusDownloadingFile = 0, "Downloading #%s#..."
#<====================================================
threadStatusDownloadingUpdate = 0, "アップデータをダウンロード中..."
threadStatusExtendingSaveData = 0, "#%s#のセーブデータを拡張中..."
threadStatusGetDirProps = 0, "フォルダプロパティの取得中..."
threadStatusOpeningFolder = 0, "#%s#を開き中..."
threadStatusPackingJKSV = 0, "JKSVフォルダの内容をZIPに書き込み中..."
threadStatusResettingSaveData = 0, "セーブデータをリストアしています..."
threadStatusSavingTranslations = 0, "Saving the file master..."
#CHANGED=============================================>
threadStatusUploadingFile = 0, "Uploading #%s#..."
#<====================================================
titleOptions = 0, "インフォメーション"
titleOptions = 1, "ブラックリスト"
titleOptions = 2, "出力フォルダを変更する"
@ -149,6 +201,11 @@ titleOptions = 4, "すべてのセーブデータバックアップを削除す
titleOptions = 5, "セーブデータをリセット"
titleOptions = 6, "セーブデータを削除"
titleOptions = 7, "セーブデータを拡張"
#CHANGED=============================================>
titleOptions = 8, "Export SVI"
#<====================================================
translationMainPage = 0, "Translation: "
userOptions = 0, "すべてをダンプする "
userOptions = 1, "セーブデータを作成"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "存档索引号:"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "系统存档\n"
saveDataTypeText = 1, "用户存档\n"
saveDataTypeText = 2, "BCAT存档\n"
saveDataTypeText = 3, "设备存档\n"
saveDataTypeText = 4, "临时存档\n"
saveDataTypeText = 5, "缓存存档\n"
saveDataTypeText = 6, "系统BCAT存档\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "存档索引号:"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "系统存档\n"
saveDataTypeText = 1, "用户存档\n"
saveDataTypeText = 2, "BCAT存档\n"
saveDataTypeText = 3, "设备存档\n"
saveDataTypeText = 4, "临时存档\n"
saveDataTypeText = 5, "缓存存档\n"
saveDataTypeText = 6, "系统BCAT存档\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "存档索引号:"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "系统存档\n"
saveDataTypeText = 1, "用户存档\n"
saveDataTypeText = 2, "BCAT存档\n"
saveDataTypeText = 3, "设备存档\n"
saveDataTypeText = 4, "临时存档\n"
saveDataTypeText = 5, "缓存存档\n"
saveDataTypeText = 6, "系统BCAT存档\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,15 @@ confirmDelete = 0, "Are you sure you want to delete #%s#? *This is permanent*!"
confirmDeleteBackupsAll = 0, "Are you sure you would like to delete *all* of your save backups for all of your games?"
confirmDeleteBackupsTitle = 0, "Are you sure you would like to delete all save backups for #%s#?"
confirmDeleteSaveData = 0, "*WARNING*: This *will* erase the save data for #%s# *from your system*. Are you sure you want to do this?"
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
confirmOverwrite = 0, "Are you sure you want to overwrite #%s#?"
confirmResetSaveData = 0, "*WARNING*: This *will* reset the save data for this game as if it was never ran before. Are you sure you want to do this?"
confirmRestore = 0, "Are you sure you want to restore #%s#?"
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
@ -35,25 +41,22 @@ fileModeMenu = 5, "Close"
fileModeMenu = 6, "Add to Path Filters"
fileModeMenuMkDir = 0, "New"
folderMenuNew = 0, "New Backup"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [B] Close"
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
helpSettings = 0, "[A] Toggle [X] Defaults [B] Back"
helpTitle = 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back"
helpUser = 0, "[A] Select [X] User Options"
helpUser = 0, "[A] Select [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "Play Time: "
infoStatus = 3, "Total Launches: "
infoStatus = 4, "User Count: "
infoStatus = 5, "Current User: "
infoStatus = 6, "Current Title: "
infoStatus = 7, "Safe Title: "
infoStatus = 8, "Sort Type: "
infoStatus = 9, "Saving the file master..."
infoStatus = 10, "Deleting..."
infoStatus = 11, "Trash emptied."
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
infoStatus = 9, ""
loadingStartPage = 0, "Loading..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Settings"
@ -63,10 +66,15 @@ popAddedToPathFilter = 0, "'#%s#' added to path filters."
popCPUBoostEnabled = 0, "CPU Boost Enabled for ZIP."
popChangeOutputError = 0, "#%s# contains illegal or non-ASCII characters."
popChangeOutputFolder = 0, "#%s# changed to #%s#"
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
popErrorCommittingFile = 0, "Error committing file to save!"
popFolderIsEmpty = 0, "Folder is empty!"
popProcessShutdown = 0, "#%s# successfully shutdown."
popSVIExported = 0, "SVI Exported."
popSaveIsEmpty = 0, "Save data is empty!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP file is empty!"
saveDataBackupDeleted = 0, "#%s# has been deleted."
saveDataBackupMovedToTrash = 0, "#%s# has been moved to trash."
@ -76,16 +84,15 @@ saveDataDeleteAllUser = 0, "*ARE YOU SURE YOU WANT TO DELETE ALL SAVE DATA FOR %
saveDataDeleteSuccess = 0, "Save data for #%s# deleted!"
saveDataExtendFailed = 0, "Failed to extend save data."
saveDataExtendSuccess = 0, "Save data for #%s# extended!"
saveDataIndexText = 0, "存档索引号:"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
saveDataTypeText = 0, "系统存档\n"
saveDataTypeText = 1, "用户存档\n"
saveDataTypeText = 2, "BCAT存档\n"
saveDataTypeText = 3, "设备存档\n"
saveDataTypeText = 4, "临时存档\n"
saveDataTypeText = 5, "缓存存档\n"
saveDataTypeText = 6, "系统BCAT存档\n"
saveDataTypeText = 0, "System"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Device"
saveDataTypeText = 4, "Temporary"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
@ -128,19 +135,24 @@ swkbdSaveIndex = 0, "Enter Cache Index"
swkbdSetWorkDir = 0, "Enter a new Output Path"
swkbdSysSavID = 0, "Enter System Save ID"
threadStatusAddingFileToZip = 0, "Adding '#%s#' to ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "Checking for updates..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "Copying '#%s#'..."
threadStatusCreatingSaveData = 0, "Creating Save Data for #%s#..."
threadStatusDecompressingFile = 0, "Decompressing '#%s#'..."
threadStatusDeletingFile = 0, "Deleting..."
threadStatusDeletingSaveData = 0, "Deleting Save Data for #%s#..."
threadStatusDeletingUpdate = 0, "Deleting pending update..."
threadStatusDownloadingFile = 0, "Downloading #%s#..."
threadStatusDownloadingUpdate = 0, "Downloading update..."
threadStatusExtendingSaveData = 0, "Extending Save Data for #%s#..."
threadStatusGetDirProps = 0, "Getting Folder Properties..."
threadStatusOpeningFolder = 0, "Opening '#%s#'..."
threadStatusPackingJKSV = 0, "Writing JKSV folder contents to ZIP..."
threadStatusResettingSaveData = 0, "Resetting save data..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "Uploading #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Change Output Folder"
@ -149,6 +161,7 @@ titleOptions = 4, "Delete All Save Backups"
titleOptions = 5, "Reset Save Data"
titleOptions = 6, "Delete Save Data"
titleOptions = 7, "Extend Save Data"
titleOptions = 8, "Export SVI"
translationMainPage = 0, "Translation: "
userOptions = 0, "Dump All For "
userOptions = 1, "Create Save Data"

View File

@ -6,9 +6,23 @@ confirmDelete = 0, "是否确定要删除#%s#*这是永久的*"
confirmDeleteBackupsAll = 0, "是否确定要删除您所有游戏的*所有*存档备份?"
confirmDeleteBackupsTitle = 0, "是否确定要删除#%s#的所有存档备份?"
confirmDeleteSaveData = 0, "*警告*:这*将从系统*中删除#%s#*的存档数据。您确定要这样做吗?"
#CHANGED=============================================>
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
#<====================================================
confirmOverwrite = 0, "是否确定要覆盖#%s#?"
confirmResetSaveData = 0, "*警告*:此*将*重置此游戏的存档数据,就像以前从未运行过一样。您确定要这样做吗?"
confirmRestore = 0, "您确定要还原#%s#吗?"
#CHANGED=============================================>
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
#<====================================================
dialogNo = 0, "否 [B]"
dialogOK = 0, "好 [A]"
dialogYes = 0, "是 [A]"
@ -35,25 +49,29 @@ fileModeMenu = 5, "关闭"
fileModeMenu = 6, "添加到路径过滤器"
fileModeMenuMkDir = 0, "新建"
folderMenuNew = 0, "新建目录"
helpFolder = 0, "[A] 选择 [Y] 恢复 [X] 删除 [B] 关闭"
#CHANGED=============================================>
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
#<====================================================
helpSettings = 0, "[A] 切换 [X] 恢复默认 [B] 返回"
helpTitle = 0, "[A] 选择 [L][R] 翻页 [Y] 收藏 [X] Title选项 [B] 返回"
helpUser = 0, "[A] 选择 [X] 用户选项"
holdingText = 0, "(按住)"
holdingText = 1, "(持续按住)"
holdingText = 2, "(快好了!)"
infoStatus = 0, "TID: "
infoStatus = 1, "SID: "
infoStatus = 2, "游戏时间:"
infoStatus = 3, "总启动次数:"
infoStatus = 4, "用户数目:"
infoStatus = 5, "当前用户:"
infoStatus = 6, "当前Title"
infoStatus = 7, "安全Title"
infoStatus = 8, "排序类型:"
infoStatus = 9, "正在文件管理器里保存..."
infoStatus = 10, "正在删除"
infoStatus = 11, "回收站已清空。"
#CHANGED=============================================>
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
#<=====================================================
loadingStartPage = 0, "加载中..."
mainMenuExtras = 0, "附加功能"
mainMenuSettings = 0, "系统设置"
@ -63,10 +81,23 @@ popAddedToPathFilter = 0, "'#%s#'添加到路径过滤器。"
popCPUBoostEnabled = 0, "为ZIP压缩启用CPU超频。"
popChangeOutputError = 0, "#%s# 包含非法或者非ASCII的字符。"
popChangeOutputFolder = 0, "#%s# 更改到 #%s#"
#CHANGED=============================================>
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
#<====================================================
popErrorCommittingFile = 0, "提交要保存的文件时出错!"
popFolderIsEmpty = 0, "文件夹为空!"
popProcessShutdown = 0, "#%s#已成功关闭。"
#CHANGED=============================================>
popSVIExported = 0, "SVI Exported."
#<====================================================
popSaveIsEmpty = 0, "存档数据为空!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP文件为空"
saveDataBackupDeleted = 0, "#%s#已被删除。"
saveDataBackupMovedToTrash = 0, "#%s#已被移到回收站。"
@ -79,13 +110,13 @@ saveDataExtendSuccess = 0, "#%s#的存档数据已扩展!"
saveDataIndexText = 0, "存档索引号:"
saveDataNoneFound = 0, "没有找到#%s#的存档!"
saveDataResetSuccess = 0, "#%s#的存档已重置!"
saveDataTypeText = 0, "系统存档\n"
saveDataTypeText = 1, "用户存档\n"
saveDataTypeText = 2, "BCAT存档\n"
saveDataTypeText = 3, "设备存档\n"
saveDataTypeText = 4, "临时存档\n"
saveDataTypeText = 5, "缓存存档\n"
saveDataTypeText = 6, "系统BCAT存档\n"
saveDataTypeText = 0, "系统存档"
saveDataTypeText = 1, "用户存档"
saveDataTypeText = 2, "BCAT存档"
saveDataTypeText = 3, "设备存档"
saveDataTypeText = 4, "临时存档"
saveDataTypeText = 5, "缓存存档"
saveDataTypeText = 6, "系统BCAT存档"
saveTypeMainMenu = 0, "设备"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "缓存"
@ -128,19 +159,40 @@ swkbdSaveIndex = 0, "请输入缓存索引号"
swkbdSetWorkDir = 0, "请输入新的输出目录"
swkbdSysSavID = 0, "请输入系统存档ID"
threadStatusAddingFileToZip = 0, "正在添加'#%s#'到ZIP文件..."
#CHANGED=============================================>
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
#<====================================================
threadStatusCheckingForUpdate = 0, "正在检查更新..."
#CHANGED=============================================>
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
#<====================================================
threadStatusCopyingFile = 0, "正在拷贝'#%s#'..."
threadStatusCreatingSaveData = 0, "正在创建#%s#的存档..."
threadStatusDecompressingFile = 0, "正在解压'#%s#'..."
threadStatusDeletingFile = 0, "正在删除..."
threadStatusDeletingSaveData = 0, "正在删除#%s#的存档..."
threadStatusDeletingUpdate = 0, "正在删除挂起的更新..."
#CHANGED=============================================>
threadStatusDownloadingFile = 0, "Downloading #%s#..."
#<====================================================
threadStatusDownloadingUpdate = 0, "正在下载更新..."
threadStatusExtendingSaveData = 0, "正在扩展#%s#的存档..."
threadStatusGetDirProps = 0, "正在获取文件夹属性..."
threadStatusOpeningFolder = 0, "正在打开'#%s#'..."
threadStatusPackingJKSV = 0, "正在写入JKSV文件夹内容到ZIP压缩包..."
threadStatusResettingSaveData = 0, "正在重置存档数据..."
threadStatusSavingTranslations = 0, "Saving the file master..."
#CHANGED=============================================>
threadStatusUploadingFile = 0, "Uploading #%s#..."
#<====================================================
titleOptions = 0, "信息"
titleOptions = 1, "黑名单"
titleOptions = 2, "更改输出目录"
@ -149,6 +201,11 @@ titleOptions = 4, "删除所有存储备份"
titleOptions = 5, "重置存档数据"
titleOptions = 6, "删除存档数据"
titleOptions = 7, "扩展存档数据"
#CHANGED=============================================>
titleOptions = 8, "Export SVI"
#<====================================================
translationMainPage = 0, "翻译:"
userOptions = 0, "转储该游戏的所有存档:"
userOptions = 1, "创建存档数据"

View File

@ -6,9 +6,23 @@ confirmDelete = 0, "是否確定要刪除#%s#? *此為永久性刪除!*"
confirmDeleteBackupsAll = 0, "是否確定要刪除你備份所有遊戲的 *全部* 存檔進度?"
confirmDeleteBackupsTitle = 0, "是否確定要刪除#%s#的全部存檔進度?"
confirmDeleteSaveData = 0, "*注意*: 此操作 *將會* 完整刪除#%s# *在主機系統內* 的存檔進度. 請再次確認是否要繼續進行?"
#CHANGED=============================================>
confirmDriveOverwrite = 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?"
#<====================================================
confirmOverwrite = 0, "是否確定要覆寫#%s#?"
confirmResetSaveData = 0, "*注意*: 此操作 *將會* 重置歸零此遊戲的存檔進度,像是從未執行過. 請再次確認是否要繼續進行?"
confirmRestore = 0, "是否確定要還原#%s#?"
#CHANGED=============================================>
debugStatus = 0, "User Count: "
debugStatus = 1, "Current User: "
debugStatus = 2, "Current Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Sort Type: "
#<====================================================
dialogNo = 0, "否 [B]"
dialogOK = 0, "確定 [A]"
dialogYes = 0, "是 [A]"
@ -35,25 +49,29 @@ fileModeMenu = 5, "關閉"
fileModeMenu = 6, "新增至路徑篩選器"
fileModeMenuMkDir = 0, "新建"
folderMenuNew = 0, "新建目錄"
helpFolder = 0, "[A] 選定 [Y] 還原 [X] 刪除 [B] 關閉"
#CHANGED=============================================>
helpFolder = 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close"
#<====================================================
helpSettings = 0, "[A] 切換 [X] 恢復預設值 [B] 返回"
helpTitle = 0, "[A] 選定 [L][R] 翻頁 [Y] 最愛 [X] Title選項 [B] 返回"
helpUser = 0, "[A] 選定 [X] 使用者選項"
holdingText = 0, "(請按住) "
holdingText = 1, "(繼續按住) "
holdingText = 2, "(確認執行!) "
infoStatus = 0, "TID:"
infoStatus = 1, "SID:"
infoStatus = 2, "遊戲時間:"
infoStatus = 3, "總啟動次數:"
infoStatus = 4, "使用者人數:"
infoStatus = 5, "目前使用者:"
infoStatus = 6, "目前Title:"
infoStatus = 7, "安全Title:"
infoStatus = 8, "排序模式:"
infoStatus = 9, "檔案管理器正在儲存…"
infoStatus = 10, "正在删除"
infoStatus = 11, "資源回收筒已清空"
#CHANGED=============================================>
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Play Time: %02d:%02d"
infoStatus = 3, "Total Launches: %u"
infoStatus = 4, "Publisher: %s"
infoStatus = 5, "Save Type: %s"
infoStatus = 6, "Cache Index: %u"
infoStatus = 7, "User: %s"
#<=====================================================
loadingStartPage = 0, "加載中…"
mainMenuExtras = 0, "附加設定"
mainMenuSettings = 0, "系統設定"
@ -63,10 +81,23 @@ popAddedToPathFilter = 0, "'#%s#' 已新增至路徑篩選器."
popCPUBoostEnabled = 0, "壓縮ZIP時將啟用CPU超頻."
popChangeOutputError = 0, "#%s# 包含非法或者非ASCII字元."
popChangeOutputFolder = 0, "#%s# 更改到 #%s#"
#CHANGED=============================================>
popDriveFailed = 0, "Failed to start Google Drive."
popDriveNotActive = 0, "Google Drive is not available"
popDriveStarted = 0, "Google Drive started successfully."
#<====================================================
popErrorCommittingFile = 0, "提交檔案進行儲存時發生錯誤!"
popFolderIsEmpty = 0, "資料夾內沒有檔案!"
popProcessShutdown = 0, "#%s# 程序已關閉."
#CHANGED=============================================>
popSVIExported = 0, "SVI Exported."
#<====================================================
popSaveIsEmpty = 0, "沒有找到存檔進度!"
popTrashEmptied = 0, "Trash emptied"
popZipIsEmpty = 0, "ZIP壓縮檔內沒有檔案!"
saveDataBackupDeleted = 0, "#%s#已被刪除."
saveDataBackupMovedToTrash = 0, "#%s#已被移動至資源回收筒."
@ -79,13 +110,13 @@ saveDataExtendSuccess = 0, "#%s#的進度存檔儲存空間已擴充!"
saveDataIndexText = 0, "存檔索引:"
saveDataNoneFound = 0, "沒有#%s#的進度存檔!"
saveDataResetSuccess = 0, "#%s#的進度存檔已重置!"
saveDataTypeText = 0, "系統存檔\n"
saveDataTypeText = 1, "使用者存檔\n"
saveDataTypeText = 2, "BCAT存檔\n"
saveDataTypeText = 3, "主機存檔\n"
saveDataTypeText = 4, "暫存資料夾\n"
saveDataTypeText = 5, "快取資料夾\n"
saveDataTypeText = 6, "系統BCAT\n"
saveDataTypeText = 0, "系統存檔"
saveDataTypeText = 1, "使用者存檔"
saveDataTypeText = 2, "BCAT存檔"
saveDataTypeText = 3, "主機存檔"
saveDataTypeText = 4, "暫存資料夾"
saveDataTypeText = 5, "快取資料夾"
saveDataTypeText = 6, "系統BCAT"
saveTypeMainMenu = 0, "設備"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "快取"
@ -128,19 +159,32 @@ swkbdSaveIndex = 0, "請輸入快取索引"
swkbdSetWorkDir = 0, "請輸入新的匯出路徑"
swkbdSysSavID = 0, "請輸入系統存檔ID"
threadStatusAddingFileToZip = 0, "正在將'#%s#'的存檔壓縮為ZIP..."
threadStatusCalculatingSaveSize = 0, "Calculating save data size..."
threadStatusCheckingForUpdate = 0, "檢查是否有可用更新..."
threadStatusCompressingSaveForUpload = 0, "Compressing #%s# for upload..."
threadStatusCopyingFile = 0, "正在複製'#%s#'..."
threadStatusCreatingSaveData = 0, "正在新增#%s#的存檔進度..."
threadStatusDecompressingFile = 0, "'#%s#'存檔正在解壓縮..."
threadStatusDeletingFile = 0, "刪除中..."
threadStatusDeletingSaveData = 0, "正在刪除#%s#的存檔進度.."
threadStatusDeletingUpdate = 0, "正在刪除系統更新..."
#CHANGED=============================================>
threadStatusDownloadingFile = 0, "Downloading #%s#..."
#<====================================================
threadStatusDownloadingUpdate = 0, "正在下載更新版本..."
threadStatusExtendingSaveData = 0, "正在擴充#%s#的存檔空間..."
threadStatusGetDirProps = 0, "正在取得資料夾屬性資訊..."
threadStatusOpeningFolder = 0, "正在開啟'#%s#'資料夾..."
threadStatusPackingJKSV = 0, "正在將JKSV資料夾壓縮為ZIP..."
threadStatusResettingSaveData = 0, "正在重置遊戲存檔進度..."
threadStatusSavingTranslations = 0, "Saving the file master..."
#CHANGED=============================================>
threadStatusUploadingFile = 0, "Uploading #%s#..."
#<====================================================
titleOptions = 0, "詳細資訊"
titleOptions = 1, "設為黑名單"
titleOptions = 2, "變更匯出檔案資料夾"
@ -149,6 +193,11 @@ titleOptions = 4, "刪除所有進度存檔"
titleOptions = 5, "重置進度存檔"
titleOptions = 6, "刪除進度存檔"
titleOptions = 7, "擴充存檔空間"
#CHANGED=============================================>
titleOptions = 8, "Export SVI"
#<====================================================
translationMainPage = 0, "翻譯:"
userOptions = 0, "備份使用者全部存檔:"
userOptions = 1, "新增遊戲存檔進度"

View File

@ -14,13 +14,16 @@ std::vector<uint64_t> cfg::blacklist;
std::vector<uint64_t> cfg::favorites;
static std::unordered_map<uint64_t, std::string> pathDefs;
uint8_t cfg::sortType;
std::string cfg::driveClientID, cfg::driveClientSecret, cfg::driveRefreshToken, cfg::driveAuthCode;
const char *cfgPath = "sdmc:/config/JKSV/JKSV.cfg", *titleDefPath = "sdmc:/config/JKSV/titleDefs.txt", *workDirLegacy = "sdmc:/switch/jksv_dir.txt";
static std::unordered_map<std::string, unsigned> cfgStrings =
{
{"workDir", 0}, {"includeDeviceSaves", 1}, {"autoBackup", 2}, {"overclock", 3}, {"holdToDelete", 4}, {"holdToRestore", 5},
{"holdToOverwrite", 6}, {"forceMount", 7}, {"accountSystemSaves", 8}, {"allowSystemSaveWrite", 9}, {"directFSCommands", 10},
{"exportToZIP", 11}, {"languageOverride", 12}, {"enableTrashBin", 13}, {"titleSortType", 14}, {"animationScale", 15},
{"favorite", 16}, {"blacklist", 17}, {"autoName", 18}
{"favorite", 16}, {"blacklist", 17}, {"autoName", 18}, {"driveClientID", 19}, {"driveClientSecret", 20}, {"driveRefreshToken", 21},
{"driveAuthCode", 22}
};
const std::string _true_ = "true", _false_ = "false";
@ -102,12 +105,13 @@ bool cfg::isDefined(const uint64_t& tid)
void cfg::pathDefAdd(const uint64_t& tid, const std::string& newPath)
{
std::string oldSafe = data::titles[tid].safeTitle;
data::titleInfo *t = data::getTitleInfoByTID(tid);
std::string oldSafe = t->safeTitle;
std::string tmp = util::safeString(newPath);
if(!tmp.empty())
{
pathDefs[tid] = tmp;
data::titles[tid].safeTitle = tmp;
t->safeTitle = tmp;
std::string oldOutput = fs::getWorkDir() + oldSafe;
std::string newOutput = fs::getWorkDir() + tmp;
@ -302,103 +306,123 @@ void cfg::loadConfig()
fs::dataFile cfgRead(cfgPath);
while(cfgRead.readNextLine(true))
{
switch(cfgStrings[cfgRead.getName()])
std::string varName = cfgRead.getName();
if(cfgStrings.find(varName) != cfgStrings.end())
{
case 0:
fs::setWorkDir(cfgRead.getNextValueStr());
break;
switch(cfgStrings[varName])
{
case 0:
fs::setWorkDir(cfgRead.getNextValueStr());
break;
case 1:
cfg::config["incDev"] = textToBool(cfgRead.getNextValueStr());
break;
case 1:
cfg::config["incDev"] = textToBool(cfgRead.getNextValueStr());
break;
case 2:
cfg::config["autoBack"] = textToBool(cfgRead.getNextValueStr());
break;
case 2:
cfg::config["autoBack"] = textToBool(cfgRead.getNextValueStr());
break;
case 3:
cfg::config["ovrClk"] = textToBool(cfgRead.getNextValueStr());
break;
case 3:
cfg::config["ovrClk"] = textToBool(cfgRead.getNextValueStr());
break;
case 4:
cfg::config["holdDel"] = textToBool(cfgRead.getNextValueStr());
break;
case 4:
cfg::config["holdDel"] = textToBool(cfgRead.getNextValueStr());
break;
case 5:
cfg::config["holdRest"] = textToBool(cfgRead.getNextValueStr());
break;
case 5:
cfg::config["holdRest"] = textToBool(cfgRead.getNextValueStr());
break;
case 6:
cfg::config["holdOver"] = textToBool(cfgRead.getNextValueStr());
break;
case 6:
cfg::config["holdOver"] = textToBool(cfgRead.getNextValueStr());
break;
case 7:
cfg::config["forceMount"] = textToBool(cfgRead.getNextValueStr());
break;
case 7:
cfg::config["forceMount"] = textToBool(cfgRead.getNextValueStr());
break;
case 8:
cfg::config["accSysSave"] = textToBool(cfgRead.getNextValueStr());
break;
case 8:
cfg::config["accSysSave"] = textToBool(cfgRead.getNextValueStr());
break;
case 9:
cfg::config["sysSaveWrite"] = textToBool(cfgRead.getNextValueStr());
break;
case 9:
cfg::config["sysSaveWrite"] = textToBool(cfgRead.getNextValueStr());
break;
case 10:
cfg::config["directFsCmd"] = textToBool(cfgRead.getNextValueStr());
break;
case 10:
cfg::config["directFsCmd"] = textToBool(cfgRead.getNextValueStr());
break;
case 11:
cfg::config["zip"] = textToBool(cfgRead.getNextValueStr());
break;
case 11:
cfg::config["zip"] = textToBool(cfgRead.getNextValueStr());
break;
case 12:
cfg::config["langOverride"] = textToBool(cfgRead.getNextValueStr());
break;
case 12:
cfg::config["langOverride"] = textToBool(cfgRead.getNextValueStr());
break;
case 13:
cfg::config["trashBin"] = textToBool(cfgRead.getNextValueStr());
break;
case 13:
cfg::config["trashBin"] = textToBool(cfgRead.getNextValueStr());
break;
case 14:
{
std::string getSort = cfgRead.getNextValueStr();
if(getSort == "ALPHA")
cfg::sortType = cfg::ALPHA;
else if(getSort == "MOST_PLAYED")
cfg::sortType = cfg::MOST_PLAYED;
else
cfg::sortType = cfg::LAST_PLAYED;
}
break;
case 14:
{
std::string getSort = cfgRead.getNextValueStr();
if(getSort == "ALPHA")
cfg::sortType = cfg::ALPHA;
else if(getSort == "MOST_PLAYED")
cfg::sortType = cfg::MOST_PLAYED;
else
cfg::sortType = cfg::LAST_PLAYED;
}
break;
case 15:
{
std::string animFloat = cfgRead.getNextValueStr();
ui::animScale = strtof(animFloat.c_str(), NULL);
}
break;
case 15:
{
std::string animFloat = cfgRead.getNextValueStr();
ui::animScale = strtof(animFloat.c_str(), NULL);
}
break;
case 16:
{
std::string tid = cfgRead.getNextValueStr();
cfg::favorites.push_back(strtoul(tid.c_str(), NULL, 16));
}
break;
case 16:
{
std::string tid = cfgRead.getNextValueStr();
cfg::favorites.push_back(strtoul(tid.c_str(), NULL, 16));
}
break;
case 17:
{
std::string tid = cfgRead.getNextValueStr();
cfg::blacklist.push_back(strtoul(tid.c_str(), NULL, 16));
}
break;
case 17:
{
std::string tid = cfgRead.getNextValueStr();
cfg::blacklist.push_back(strtoul(tid.c_str(), NULL, 16));
}
break;
case 18:
cfg::config["autoName"] = textToBool(cfgRead.getNextValueStr());
break;
case 18:
cfg::config["autoName"] = textToBool(cfgRead.getNextValueStr());
break;
default:
break;
case 19:
cfg::driveClientID = cfgRead.getNextValueStr();
break;
case 20:
cfg::driveClientSecret = cfgRead.getNextValueStr();
break;
case 21:
cfg::driveRefreshToken = cfgRead.getNextValueStr();
break;
case 22:
cfg::driveAuthCode = cfgRead.getNextValueStr();
break;
default:
break;
}
}
}
}
@ -433,6 +457,15 @@ void cfg::saveConfig()
fprintf(cfgOut, "titleSortType = %s\n", sortTypeText().c_str());
fprintf(cfgOut, "animationScale = %f\n", ui::animScale);
if(!cfg::driveClientID.empty())
fprintf(cfgOut, "driveClientID = %s\n", cfg::driveClientID.c_str());
if(!cfg::driveClientSecret.empty())
fprintf(cfgOut, "driveClientSecret = %s\n", cfg::driveClientSecret.c_str());
if(!cfg::driveRefreshToken.empty())
fprintf(cfgOut, "driveRefreshToken = %s\n", cfg::driveRefreshToken.c_str());
if(!cfg::favorites.empty())
{
fprintf(cfgOut, "\n#favorites\n");

View File

@ -2,21 +2,54 @@
#include <vector>
#include <curl/curl.h>
size_t writeDataString(const char *buff, size_t sz, size_t cnt, void *u)
#include "curlfuncs.h"
#include "util.h"
size_t curlFuncs::writeDataString(const char *buff, size_t sz, size_t cnt, void *u)
{
std::string *str = (std::string *)u;
str->append(buff, 0, sz * cnt);
return sz * cnt;
}
size_t writeDataHead(const char *buff, size_t sz, size_t cnt, void *u)
size_t curlFuncs::writeHeaders(const char *buff, size_t sz, size_t cnt, void *u)
{
std::vector<std::string> *headers = (std::vector<std::string> *)u;
headers->push_back(buff);
return sz * cnt;
}
std::string getJSONURL(std::vector<std::string> *headers, const std::string& _url)
size_t curlFuncs::readDataFile(char *buff, size_t sz, size_t cnt, void *u)
{
curlFuncs::curlUpArgs*in = (curlFuncs::curlUpArgs *)u;
size_t ret = fread(buff, sz, cnt, in->f);
if(in->o)
*in->o = ftell(in->f);
return ret;
}
std::string curlFuncs::getHeader(const std::string& name, std::vector<std::string> *h)
{
std::string ret = HEADER_ERROR;
for (unsigned i = 0; i < h->size(); i++)
{
std::string curHeader = h->at(i);
size_t colonPos = curHeader.find_first_of(':');
if (curHeader.substr(0, colonPos) == name)
{
ret = curHeader.substr(colonPos + 2);
break;
}
}
util::stripChar('\n', ret);
util::stripChar('\r', ret);
return ret;
}
std::string curlFuncs::getJSONURL(std::vector<std::string> *headers, const std::string& _url)
{
std::string ret;
CURL *handle = curl_easy_init();
@ -29,7 +62,7 @@ std::string getJSONURL(std::vector<std::string> *headers, const std::string& _ur
curl_easy_setopt(handle, CURLOPT_TIMEOUT, 15);
if(headers)
{
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, writeDataHead);
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, writeHeaders);
curl_easy_setopt(handle, CURLOPT_HEADERDATA, headers);
}
@ -49,7 +82,7 @@ size_t writeDataBin(uint8_t *buff, size_t sz, size_t cnt, void *u)
return sizeIn;
}
bool getBinURL(std::vector<uint8_t> *out, const std::string& _url)
bool curlFuncs::getBinURL(std::vector<uint8_t> *out, const std::string& _url)
{
bool ret = false;
CURL *handle = curl_easy_init();

View File

@ -27,7 +27,6 @@ SetLanguage data::sysLang;
//For other save types
static bool sysBCATPushed = false, tempPushed = false;
std::unordered_map<uint64_t, data::titleInfo> data::titles;
static SDL_Texture *iconMask;
//Sorts titles by sortType
static struct
@ -118,7 +117,10 @@ static inline void addTitleToList(const uint64_t& tid)
//Setup 'shortcuts' to strings
NacpLanguageEntry *ent;
nacpGetLanguageEntry(&data::titles[tid].nacp, &ent);
data::titles[tid].title = ent->name;
if(strlen(ent->name) == 0)
data::titles[tid].title = ctrlData->nacp.lang[SetLanguage_ENUS].name;
else
data::titles[tid].title = ent->name;
data::titles[tid].author = ent->author;
if(cfg::isDefined(tid))
data::titles[tid].safeTitle = cfg::getPathDefinition(tid);
@ -127,7 +129,7 @@ static inline void addTitleToList(const uint64_t& tid)
if(cfg::isFavorite(tid))
data::titles[tid].fav = true;
data::titles[tid].icon = gfx::loadJPEGMem(ctrlData->icon, iconSize);
if(!data::titles[tid].icon)
data::titles[tid].icon = util::createIconGeneric(util::getIDStrLower(tid).c_str(), 32, true);
@ -178,6 +180,52 @@ static void loadTitlesFromRecords()
}
}
static void importSVIs()
{
std::string sviDir = fs::getWorkDir() + "svi/";
fs::dirList sviList(sviDir);
if(sviList.getCount() > 0)
{
for(unsigned i = 0; i < sviList.getCount(); i++)
{
uint64_t tid = 0;
NacpStruct *nacp = new NacpStruct;
NacpLanguageEntry *ent;
std::string sviPath = fs::getWorkDir() + "svi/" + sviList.getItem(i);
size_t iconSize = fs::fsize(sviPath) - (sizeof(uint64_t) + sizeof(NacpStruct));
uint8_t *iconBuffer = new uint8_t[iconSize];
FILE *sviIn = fopen(sviPath.c_str(), "rb");
fread(&tid, sizeof(uint64_t), 1, sviIn);
fread(nacp, sizeof(NacpStruct), 1, sviIn);
fread(iconBuffer, 1, iconSize, sviIn);
if(!titleIsLoaded(tid))
{
nacpGetLanguageEntry(nacp, &ent);
memcpy(&data::titles[tid].nacp, nacp, sizeof(NacpStruct));
data::titles[tid].title = ent->name;
data::titles[tid].author = ent->author;
if(cfg::isDefined(tid))
data::titles[tid].safeTitle = cfg::getPathDefinition(tid);
else if((data::titles[tid].safeTitle = util::safeString(ent->name)) == "")
data::titles[tid].safeTitle = util::getIDStr(tid);
if(cfg::isFavorite(tid))
data::titles[tid].fav = true;
if(!data::titles[tid].icon && iconSize > 0)
data::titles[tid].icon = gfx::loadJPEGMem(iconBuffer, iconSize);
else if(!data::titles[tid].icon && iconSize == 0)
data::titles[tid].icon = util::createIconGeneric(util::getIDStrLower(tid).c_str(), 32, true);
}
delete nacp;
delete[] iconBuffer;
fclose(sviIn);
}
}
}
bool data::loadUsersTitles(bool clearUsers)
{
static unsigned systemUserCount = 4;
@ -186,6 +234,7 @@ bool data::loadUsersTitles(bool clearUsers)
s64 total = 0;
loadTitlesFromRecords();
importSVIs();
//Clear titles
for(data::user& u : data::users)
@ -305,9 +354,6 @@ void data::sortUserTitles()
void data::init()
{
if(cfg::config["ovrClk"])
util::setCPU(util::CPU_SPEED_1224MHz);
data::loadUsersTitles(true);
}
@ -316,11 +362,6 @@ void data::exit()
for(data::user& u : data::users) u.delIcon();
for(auto& tinfo : titles)
SDL_DestroyTexture(tinfo.second.icon);
SDL_DestroyTexture(iconMask);
if(cfg::config["ovrClk"])
util::setCPU(util::CPU_SPEED_1020MHz);
}
void data::setUserIndex(unsigned _sUser)
@ -460,4 +501,4 @@ void data::dispStats()
stats += ui::getUICString("debugStatus", 3) + data::getTitleSafeNameByTID(d->tid) + "\n";
stats += ui::getUICString("debugStatus", 4) + std::to_string(cfg::sortType) + "\n";
gfx::drawTextf(NULL, 16, 2, 2, &green, stats.c_str());
}
}

View File

@ -431,7 +431,7 @@ void fs::createNewBackup(void *a)
path += "/";
fs::copyDirToDirThreaded("sv:/", path);
}
ui::populateFldMenu();
ui::fldRefreshMenu(false);
}
}
@ -537,7 +537,7 @@ void fs::restoreBackup(void *a)
}
}
if(cfg::config["autoBack"])
ui::populateFldMenu();
ui::fldRefreshMenu(false);
delete restore;
t->finished = true;
@ -572,7 +572,7 @@ void fs::deleteBackup(void *a)
fs::delfile(*deletePath);
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str());
}
ui::populateFldMenu();
ui::fldRefreshMenu(false);
delete deletePath;
t->finished = true;
}

47
src/fs/drive.cpp Normal file
View File

@ -0,0 +1,47 @@
#include "drive.h"
#include "cfg.h"
#include "ui.h"
drive::gd *fs::gDrive = NULL;
void fs::driveInit()
{
if(!cfg::driveClientID.empty() && !cfg::driveClientSecret.empty())
{
fs::gDrive = new drive::gd(cfg::driveClientID, cfg::driveClientSecret, cfg::driveAuthCode, cfg::driveRefreshToken);
if(!fs::gDrive->hasToken())
{
delete fs::gDrive;
fs::gDrive = NULL;
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveFailed", 0));
}
else
{
if(!cfg::driveAuthCode.empty() && fs::gDrive->hasToken())
{
cfg::driveRefreshToken = fs::gDrive->getRefreshToken();
cfg::saveConfig();
}
fs::gDrive->loadDriveList("name = 'JKSV'");
if(!fs::gDrive->dirExists("JKSV"))
fs::gDrive->createDir("JKSV");
std::string jksvID = fs::gDrive->getFileID("JKSV");
fs::gDrive->setRootDir(jksvID);
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveStarted", 0));
}
}
}
void fs::driveExit()
{
if(fs::gDrive)
{
//Need to save for config if first run
cfg::driveRefreshToken = fs::gDrive->getRefreshToken();
delete gDrive;
}
}

View File

@ -5,6 +5,8 @@
#include <switch.h>
#include <unistd.h>
#include <cstdarg>
#include <mutex>
#include <condition_variable>
#include <sys/stat.h>
#include "fs.h"
@ -16,6 +18,69 @@
static std::string wd = "sdmc:/JKSV/";
typedef struct
{
std::mutex bufferLock;
std::condition_variable cond;
std::vector<uint8_t> sharedBuffer;
std::string dst, dev;
bool bufferIsFull = false;
unsigned int filesize = 0, writeLimit = 0;
} fileCpyThreadArgs;
static void writeFile_t(void *a)
{
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
size_t written = 0;
std::vector<uint8_t> localBuffer;
FILE *out = fopen(in->dst.c_str(), "wb");
while(written < in->filesize)
{
std::unique_lock<std::mutex> buffLock(in->bufferLock);
in->cond.wait(buffLock, [in]{ return in->bufferIsFull;});
localBuffer.clear();
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
in->sharedBuffer.clear();
in->bufferIsFull = false;
buffLock.unlock();
in->cond.notify_one();
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
}
fclose(out);
}
static void writeFileCommit_t(void *a)
{
fileCpyThreadArgs *in = (fileCpyThreadArgs *)a;
size_t written = 0, journalCount = 0;
std::vector<uint8_t> localBuffer;
FILE *out = fopen(in->dst.c_str(), "wb");
while(written < in->filesize)
{
std::unique_lock<std::mutex> buffLock(in->bufferLock);
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
localBuffer.clear();
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
in->sharedBuffer.clear();
in->bufferIsFull = false;
buffLock.unlock();
in->cond.notify_one();
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
journalCount += written;
if(journalCount >= in->writeLimit)
{
journalCount = 0;
fclose(out);
fs::commitToDevice(in->dev.c_str());
out = fopen(in->dst.c_str(), "ab");
}
}
fclose(out);
}
fs::copyArgs *fs::copyArgsCreate(const std::string& src, const std::string& dst, const std::string& dev, zipFile z, unzFile unz, bool _cleanup, bool _trimZipPath, uint8_t _trimPlaces)
{
copyArgs *ret = new copyArgs;
@ -122,62 +187,53 @@ int fs::dataFile::getNextValueInt()
void fs::copyFile(const std::string& src, const std::string& dst, threadInfo *t)
{
fs::copyArgs *c = NULL;
size_t filesize = fs::fsize(src);
if(t)
{
c = (fs::copyArgs *)t->argPtr;
c->offset = 0;
c->prog->setMax(fs::fsize(src));
c->prog->setMax(filesize);
c->prog->update(0);
}
if(cfg::config["directFsCmd"])
FILE *fsrc = fopen(src.c_str(), "rb");
if(!fsrc)
{
FSFILE *fsrc = fsfopen(src.c_str(), FsOpenMode_Read);
FSFILE *fdst = fsfopen(dst.c_str(), FsOpenMode_Write);
if(!fsrc || !fdst)
{
fsfclose(fsrc);
fsfclose(fdst);
return;
}
uint8_t *buff = new uint8_t[BUFF_SIZE];
size_t readIn = 0;
while((readIn = fsfread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
fsfwrite(buff, 1, readIn, fdst);
if(c)
c->offset += readIn;
}
fsfclose(fsrc);
fsfclose(fdst);
delete[] buff;
}
else
{
FILE *fsrc = fopen(src.c_str(), "rb");
FILE *fdst = fopen(dst.c_str(), "wb");
if(!fsrc || !fdst)
{
fclose(fsrc);
fclose(fdst);
return;
}
uint8_t *buff = new uint8_t[BUFF_SIZE];
size_t readIn = 0;
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
fwrite(buff, 1, readIn, fdst);
if(c)
c->offset += readIn;
}
fclose(fsrc);
fclose(fdst);
delete[] buff;
return;
}
fileCpyThreadArgs thrdArgs;
thrdArgs.dst = dst;
thrdArgs.filesize = filesize;
uint8_t *buff = new uint8_t[BUFF_SIZE];
std::vector<uint8_t> transferBuffer;
Thread writeThread;
threadCreate(&writeThread, writeFile_t, &thrdArgs, NULL, 0x8000, 0x2B, 2);
threadStart(&writeThread);
size_t readIn = 0;
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
if(c)
c->offset += readIn;
if(transferBuffer.size() > TRANSFER_BUFFER_LIMIT || readIn < BUFF_SIZE)
{
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
transferBuffer.clear();
thrdArgs.bufferIsFull = true;
buffLock.unlock();
thrdArgs.cond.notify_one();
}
}
threadWaitForExit(&writeThread);
threadClose(&writeThread);
fclose(fsrc);
delete[] buff;
}
static void copyFileThreaded_t(void *a)
@ -202,88 +258,59 @@ void fs::copyFileThreaded(const std::string& src, const std::string& dst)
void fs::copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t)
{
fs::copyArgs *c = NULL;
size_t filesize = fs::fsize(src);
if(t)
{
c = (fs::copyArgs *)t->argPtr;
c->offset = 0;
c->prog->setMax(fs::fsize(src));
c->prog->setMax(filesize);
c->prog->update(0);
}
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
uint64_t journ = fs::getJournalSize(utinfo);
if(cfg::config["directFsCmd"])
FILE *fsrc = fopen(src.c_str(), "rb");
if(!fsrc)
{
FSFILE *fsrc = fsfopen(src.c_str(), FsOpenMode_Read);
FSFILE *fdst = fsfopen(dst.c_str(), FsOpenMode_Write);
if(!fsrc || !fdst)
{
fsfclose(fsrc);
fsfclose(fdst);
return;
}
uint8_t *buff = new uint8_t[BUFF_SIZE];
size_t readIn = 0, writeCount = 0;
while((readIn = fsfread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
fsfwrite(buff, 1, readIn, fdst);
writeCount += readIn;
if(c)
c->offset += readIn;
if(writeCount >= (journ - 0x100000))
{
writeCount = 0;
fsfclose(fdst);
if(!fs::commitToDevice(dev.c_str()))
break;
fdst = fsfopen(dst.c_str(), FsOpenMode_Write | FsOpenMode_Append);
}
}
fsfclose(fsrc);
fsfclose(fdst);
fs::commitToDevice(dev);
delete[] buff;
}
else
{
FILE *fsrc = fopen(src.c_str(), "rb");
FILE *fdst = fopen(dst.c_str(), "wb");
if(!fsrc || !fdst)
{
fclose(fsrc);
fclose(fdst);
return;
}
uint8_t *buff = new uint8_t[BUFF_SIZE];
size_t readIn = 0, writeCount = 0;
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
fwrite(buff, 1, readIn, fdst);
writeCount += readIn;
if(c)
c->offset += readIn;
if(writeCount >= (journ - 0x100000))
{
writeCount = 0;
fclose(fdst);
if(!fs::commitToDevice(dev))
break;
fdst = fopen(dst.c_str(), "ab");
}
}
fclose(fsrc);
fclose(fdst);
fs::commitToDevice(dev);
delete[] buff;
return;
}
fileCpyThreadArgs thrdArgs;
thrdArgs.dst = dst;
thrdArgs.dev = dev;
thrdArgs.filesize = filesize;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
uint64_t journalSpace = fs::getJournalSize(utinfo);
thrdArgs.writeLimit = (journalSpace - 0x100000) < TRANSFER_BUFFER_LIMIT ? journalSpace - 0x100000 : TRANSFER_BUFFER_LIMIT;
Thread writeThread;
threadCreate(&writeThread, writeFileCommit_t, &thrdArgs, NULL, 0x8000, 0x2B, 2);
uint8_t *buff = new uint8_t[BUFF_SIZE];
size_t readIn = 0;
std::vector<uint8_t> transferBuffer;
threadStart(&writeThread);
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
if(c)
c->offset += readIn;
if(transferBuffer.size() >= thrdArgs.writeLimit || readIn < BUFF_SIZE)
{
std::unique_lock<std::mutex> buffLock(thrdArgs.bufferLock);
thrdArgs.cond.wait(buffLock, [&thrdArgs]{ return thrdArgs.bufferIsFull == false; });
thrdArgs.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
transferBuffer.clear();
thrdArgs.bufferIsFull = true;
buffLock.unlock();
thrdArgs.cond.notify_one();
}
}
threadWaitForExit(&writeThread);
threadClose(&writeThread);
fclose(fsrc);
fs::commitToDevice(dev);
delete[] buff;
}
static void copyFileCommit_t(void *a)

View File

@ -1,8 +1,57 @@
#include <switch.h>
#include <time.h>
#include <mutex>
#include <vector>
#include <condition_variable>
#include "fs.h"
#include "util.h"
#include "cfg.h"
typedef struct
{
std::mutex buffLock;
std::condition_variable cond;
std::vector<uint8_t> sharedBuffer;
std::string dst, dev;
bool bufferIsFull = false;
unzFile unz;
unsigned int fileSize, writeLimit = 0;
} unzThrdArgs;
static void writeFileFromZip_t(void *a)
{
unzThrdArgs *in = (unzThrdArgs *)a;
std::vector<uint8_t> localBuffer;
unsigned int written = 0, journalCount = 0;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
uint64_t journalSpace = fs::getJournalSize(utinfo);
FILE *out = fopen(in->dst.c_str(), "wb");
while(written < in->fileSize)
{
std::unique_lock<std::mutex> buffLock(in->buffLock);
in->cond.wait(buffLock, [in]{ return in->bufferIsFull; });
localBuffer.clear();
localBuffer.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
in->sharedBuffer.clear();
in->bufferIsFull = false;
buffLock.unlock();
in->cond.notify_one();
written += fwrite(localBuffer.data(), 1, localBuffer.size(), out);
journalCount += written;
if(journalCount >= in->writeLimit)
{
journalCount = 0;
fclose(out);
fs::commitToDevice(in->dev);
out = fopen(in->dst.c_str(), "ab");
}
}
fclose(out);
}
void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t)
{
@ -56,8 +105,8 @@ void fs::copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int tr
FILE *fsrc = fopen(fullSrc.c_str(), "rb");
size_t readIn = 0;
uint8_t *buff = new uint8_t[BUFF_SIZE];
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
uint8_t *buff = new uint8_t[ZIP_BUFF_SIZE];
while((readIn = fread(buff, 1, ZIP_BUFF_SIZE, fsrc)) > 0)
{
zipWriteInFileInZip(dst, buff, readIn);
if(c)
@ -74,7 +123,17 @@ void copyDirToZip_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *c = (fs::copyArgs *)t->argPtr;
if(cfg::config["ovrClk"])
{
util::sysBoost();
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0));
}
fs::copyDirToZip(c->src, c->z, c->trimZipPath, c->trimZipPlaces, t);
if(cfg::config["ovrClk"])
util::sysNormal();
if(c->cleanup)
{
zipClose(c->z, NULL);
@ -119,23 +178,36 @@ void fs::copyZipToDir(unzFile src, const std::string& dst, const std::string& de
std::string fullDst = dst + filename;
fs::mkDirRec(fullDst.substr(0, fullDst.find_last_of('/') + 1));
FILE *fdst = fopen(fullDst.c_str(), "wb");
unzThrdArgs unzThrd;
unzThrd.dst = fullDst;
unzThrd.fileSize = info.uncompressed_size;
unzThrd.dev = dev;
unzThrd.writeLimit = (journalSize - 0x100000) < TRANSFER_BUFFER_LIMIT ? (journalSize - 0x100000) : TRANSFER_BUFFER_LIMIT;
Thread writeThread;
threadCreate(&writeThread, writeFileFromZip_t, &unzThrd, NULL, 0x8000, 0x2B, 2);
threadStart(&writeThread);
std::vector<uint8_t> transferBuffer;
while((readIn = unzReadCurrentFile(src, buff, BUFF_SIZE)) > 0)
{
c->offset += readIn;
writeCount += readIn;
fwrite(buff, 1, readIn, fdst);
if(writeCount >= journalSize - 0x100000)
{
writeCount = 0;
fclose(fdst);
if(!fs::commitToDevice(dev))
break;
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
fdst = fopen(fullDst.c_str(), "ab");
if(c)
c->offset += readIn;
if(transferBuffer.size() >= unzThrd.writeLimit || readIn < BUFF_SIZE)
{
std::unique_lock<std::mutex> buffLock(unzThrd.buffLock);
unzThrd.cond.wait(buffLock, [&unzThrd]{ return unzThrd.bufferIsFull == false; });
unzThrd.sharedBuffer.assign(transferBuffer.begin(), transferBuffer.end());
transferBuffer.clear();
unzThrd.bufferIsFull = true;
unzThrd.cond.notify_one();
}
}
fclose(fdst);
threadWaitForExit(&writeThread);
threadClose(&writeThread);
fs::commitToDevice(dev);
}
}

638
src/gd.cpp Normal file
View File

@ -0,0 +1,638 @@
#include <stdio.h>
#include <curl/curl.h>
#include <json-c/json.h>
#include <string>
#include <vector>
#include <mutex>
#include <condition_variable>
#include "gd.h"
#include "fs.h"
#include "curlfuncs.h"
#include "util.h"
/*
Google Drive code for JKSV.
Still major WIP
*/
#define DRIVE_UPLOAD_BUFFER_SIZE 0x8000
#define DRIVE_DOWNLOAD_BUFFER_SIZE 0xA00000
#define tokenURL "https://oauth2.googleapis.com/token"
#define tokenCheckURL "https://oauth2.googleapis.com/tokeninfo"
#define driveURL "https://www.googleapis.com/drive/v3/files"
#define driveUploadURL "https://www.googleapis.com/upload/drive/v3/files"
#define userAgent "JKSV"
std::vector<uint8_t> downloadBuffer;
typedef struct
{
curlFuncs::curlDlArgs *cfa;
std::mutex dataLock;
std::condition_variable cond;
std::vector<uint8_t> sharedBuffer;
bool bufferFull = false;
unsigned int downloaded = 0;
} dlWriteThreadStruct;
static inline void writeDriveError(const std::string& _function, const std::string& _message)
{
fs::logWrite("Drive/%s: %s\n", _function.c_str(), _message.c_str());
}
static inline void writeCurlError(const std::string& _function, int _cerror)
{
fs::logWrite("Drive/%s: CURL returned error %i\n", _function.c_str(), _cerror);
}
static void writeThread_t(void *a)
{
dlWriteThreadStruct *in = (dlWriteThreadStruct *)a;
std::vector<uint8_t> localBuff;
int written = 0;
FILE *out = fopen(in->cfa->path.c_str(), "wb");
while(written < in->cfa->size)
{
std::unique_lock<std::mutex> dataLock(in->dataLock);
in->cond.wait(dataLock, [in]{ return in->bufferFull; });
localBuff.clear();
localBuff.assign(in->sharedBuffer.begin(), in->sharedBuffer.end());
in->sharedBuffer.clear();
in->bufferFull = false;
dataLock.unlock();
in->cond.notify_one();
written += fwrite(localBuff.data(), 1, localBuff.size(), out);
}
fclose(out);
downloadBuffer.clear();
}
static size_t writeDataBufferThreaded(uint8_t *buff, size_t sz, size_t cnt, void *u)
{
dlWriteThreadStruct *in = (dlWriteThreadStruct *)u;
downloadBuffer.insert(downloadBuffer.end(), buff, buff + (sz * cnt));
in->downloaded += sz * cnt;
if(in->downloaded == in->cfa->size || (downloadBuffer.size() >= DRIVE_DOWNLOAD_BUFFER_SIZE))
{
std::unique_lock<std::mutex> dataLock(in->dataLock);
in->cond.wait(dataLock, [in]{ return in->bufferFull == false; });
in->sharedBuffer.assign(downloadBuffer.begin(), downloadBuffer.end());
downloadBuffer.clear();
in->bufferFull = true;
dataLock.unlock();
in->cond.notify_one();
}
if(in->cfa->o)
*in->cfa->o = in->downloaded;
return sz * cnt;
}
drive::gd::gd(const std::string &_clientID, const std::string& _secretID, const std::string& _authCode, const std::string& _rToken)
{
clientID = _clientID;
secretID = _secretID;
rToken = _rToken;
if(!_authCode.empty())
exhangeAuthCode(_authCode);
else if(!rToken.empty())
refreshToken();
else
writeDriveError("gd::gd", "Missing data needed to init Google Drive.\n");
}
void drive::gd::exhangeAuthCode(const std::string& _authCode)
{
// Header
curl_slist *postHeader = NULL;
postHeader = curl_slist_append(postHeader, HEADER_CONTENT_TYPE_APP_JSON);
// Post json
json_object *post = json_object_new_object();
json_object *clientIDString = json_object_new_string(clientID.c_str());
json_object *secretIDString = json_object_new_string(secretID.c_str());
json_object *authCodeString = json_object_new_string(_authCode.c_str());
json_object *redirectUriString = json_object_new_string("urn:ietf:wg:oauth:2.0:oob");
json_object *grantTypeString = json_object_new_string("authorization_code");
json_object_object_add(post, "client_id", clientIDString);
json_object_object_add(post, "client_secret", secretIDString);
json_object_object_add(post, "code", authCodeString);
json_object_object_add(post, "redirect_uri", redirectUriString);
json_object_object_add(post, "grant_type", grantTypeString);
// Curl Request
std::string *jsonResp = new std::string;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeader);
curl_easy_setopt(curl, CURLOPT_URL, tokenURL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_get_string(post));
int error = curl_easy_perform(curl);
json_object *respParse = json_tokener_parse(jsonResp->c_str());
if (error == CURLE_OK)
{
json_object *accessToken = json_object_object_get(respParse, "access_token");
json_object *refreshToken = json_object_object_get(respParse, "refresh_token");
if(accessToken && refreshToken)
{
token = json_object_get_string(accessToken);
rToken = json_object_get_string(refreshToken);
}
else
writeDriveError("exchangeAuthCode", "Error exchanging code for token.");
}
else
writeCurlError("exchangeAuthCode", error);
delete jsonResp;
json_object_put(post);
json_object_put(respParse);
curl_slist_free_all(postHeader);
curl_easy_cleanup(curl);
}
void drive::gd::refreshToken()
{
// Header
curl_slist *header = NULL;
header = curl_slist_append(header, HEADER_CONTENT_TYPE_APP_JSON);
// Post Json
json_object *post = json_object_new_object();
json_object *clientIDString = json_object_new_string(clientID.c_str());
json_object *secretIDString = json_object_new_string(secretID.c_str());
json_object *refreshTokenString = json_object_new_string(rToken.c_str());
json_object *grantTypeString = json_object_new_string("refresh_token");
json_object_object_add(post, "client_id", clientIDString);
json_object_object_add(post, "client_secret", secretIDString);
json_object_object_add(post, "refresh_token", refreshTokenString);
json_object_object_add(post, "grant_type", grantTypeString);
// Curl
std::string *jsonResp = new std::string;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, header);
curl_easy_setopt(curl, CURLOPT_URL, tokenURL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_get_string(post));
int error = curl_easy_perform(curl);
json_object *parse = json_tokener_parse(jsonResp->c_str());
if (error == CURLE_OK)
{
json_object *accessToken;
json_object_object_get_ex(parse, "access_token", &accessToken);
if(accessToken)
token = json_object_get_string(accessToken);
else
writeDriveError("refreshToken", "Error refreshing token.");
}
delete jsonResp;
json_object_put(post);
json_object_put(parse);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
}
bool drive::gd::tokenIsValid()
{
bool ret = false;
std::string url = tokenCheckURL;
url.append("?access_token=" + token);
CURL *curl = curl_easy_init();
std::string *jsonResp = new std::string;
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
int error = curl_easy_perform(curl);
json_object *parse = json_tokener_parse(jsonResp->c_str());
if (error == CURLE_OK)
{
json_object *checkError;
json_object_object_get_ex(parse, "error", &checkError);
if(!checkError)
ret = true;
}
delete jsonResp;
json_object_put(parse);
curl_easy_cleanup(curl);
return ret;
}
void drive::gd::loadDriveList(const std::string& _qParams)
{
if(!tokenIsValid())
refreshToken();
// Request url with specific fields needed.
std::string url = driveURL, queryParams = "trashed=false and 'me' in owners ";
//These are always used
url.append("?fields=files(name,id,mimeType,size,parents)&q=");
if(!parentDir.empty())
queryParams.append("and '" + parentDir + "' in parents ");
if(!_qParams.empty())
queryParams.append("and " + _qParams);
// Headers needed
curl_slist *postHeaders = NULL;
postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
// Curl request
std::string *jsonResp = new std::string;
CURL *curl = curl_easy_init();
//I don't understand why this needs a CURL handle...
char *urlAppend = curl_easy_escape(curl, queryParams.c_str(), queryParams.length());
url.append(urlAppend);
curl_free(urlAppend);
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
int error = curl_easy_perform(curl);
json_object *parse = json_tokener_parse(jsonResp->c_str());
if (error == CURLE_OK)
{
driveList.clear();
json_object *fileArray;
json_object_object_get_ex(parse, "files", &fileArray);
if(fileArray)
{
size_t count = json_object_array_length(fileArray);
driveList.reserve(count);
for (unsigned i = 0; i < count; i++)
{
json_object *idString, *nameString, *mimeTypeString, *size, *parentArray;
json_object *curFile = json_object_array_get_idx(fileArray, i);
json_object_object_get_ex(curFile, "id", &idString);
json_object_object_get_ex(curFile, "name", &nameString);
json_object_object_get_ex(curFile, "mimeType", &mimeTypeString);
json_object_object_get_ex(curFile, "size", &size);
json_object_object_get_ex(curFile, "parents", &parentArray);
drive::gdDirItem newDirItem;
newDirItem.name = json_object_get_string(nameString);
newDirItem.id = json_object_get_string(idString);
newDirItem.mimeType = json_object_get_string(mimeTypeString);
newDirItem.size = json_object_get_int(size);
if (parentArray)
{
size_t parentCount = json_object_array_length(parentArray);
for (unsigned j = 0; j < parentCount; j++)
{
json_object *parent = json_object_array_get_idx(parentArray, j);
newDirItem.parents.push_back(json_object_get_string(parent));
}
}
driveList.push_back(newDirItem);
}
}
else
writeDriveError("updateList", "Error obtaining drive listing.");
}
else
writeCurlError("updateList", error);
delete jsonResp;
json_object_put(parse);
curl_slist_free_all(postHeaders);
curl_easy_cleanup(curl);
}
void drive::gd::debugWriteList()
{
fs::logWrite("Parent: %s\n", parentDir.c_str());
for(auto& di : driveList)
{
fs::logWrite("%s\n\t%s\n", di.name.c_str(), di.id.c_str());
if(!di.parents.empty())
fs::logWrite("\t%s\n", di.parents[0].c_str());
}
}
bool drive::gd::createDir(const std::string& _dirName)
{
if(!tokenIsValid())
refreshToken();
bool ret = true;
// Headers to use
curl_slist *postHeaders = NULL;
postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
postHeaders = curl_slist_append(postHeaders, HEADER_CONTENT_TYPE_APP_JSON);
// JSON To Post
json_object *post = json_object_new_object();
json_object *nameString = json_object_new_string(_dirName.c_str());
json_object *mimeTypeString = json_object_new_string(MIMETYPE_FOLDER);
json_object_object_add(post, "name", nameString);
json_object_object_add(post, "mimeType", mimeTypeString);
if (!parentDir.empty())
{
json_object *parentsArray = json_object_new_array();
json_object *parentString = json_object_new_string(parentDir.c_str());
json_object_array_add(parentsArray, parentString);
json_object_object_add(post, "parents", parentsArray);
}
// Curl Request
std::string *jsonResp = new std::string;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders);
curl_easy_setopt(curl, CURLOPT_URL, driveURL);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_get_string(post));
int error = curl_easy_perform(curl);
json_object *respParse = json_tokener_parse(jsonResp->c_str()), *checkError;
json_object_object_get_ex(respParse, "error", &checkError);
if (error == CURLE_OK && !checkError)
{
//Append it to list
json_object *id;
json_object_object_get_ex(respParse, "id", &id);
drive::gdDirItem newDir;
newDir.name = _dirName;
newDir.id = json_object_get_string(id);
newDir.mimeType = MIMETYPE_FOLDER;
newDir.size = 0;
driveList.push_back(newDir);
}
else
ret = false;
delete jsonResp;
json_object_put(post);
json_object_put(respParse);
curl_slist_free_all(postHeaders);
curl_easy_cleanup(curl);
return ret;
}
bool drive::gd::dirExists(const std::string& _dirName)
{
bool ret = false;
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].name == _dirName && driveList[i].mimeType == MIMETYPE_FOLDER)
{
ret = true;
break;
}
}
return ret;
}
bool drive::gd::fileExists(const std::string& _filename)
{
bool ret = false;
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].name == _filename && driveList[i].mimeType != MIMETYPE_FOLDER)
{
ret = true;
break;
}
}
return ret;
}
void drive::gd::uploadFile(const std::string& _filename, curlFuncs::curlUpArgs *_upload)
{
if(!tokenIsValid())
refreshToken();
std::string url = driveUploadURL;
url.append("?uploadType=resumable");
// Headers
curl_slist *postHeaders = NULL;
postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
postHeaders = curl_slist_append(postHeaders, HEADER_CONTENT_TYPE_APP_JSON);
// Post JSON
json_object *post = json_object_new_object();
json_object *nameString = json_object_new_string(_filename.c_str());
json_object_object_add(post, "name", nameString);
if (!parentDir.empty())
{
json_object *parentArray = json_object_new_array();
json_object *parentString = json_object_new_string(parentDir.c_str());
json_object_array_add(parentArray, parentString);
json_object_object_add(post, "parents", parentArray);
}
// Curl upload request
std::string *jsonResp = new std::string;
std::vector<std::string> *headers = new std::vector<std::string>;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_HTTPPOST, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, postHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlFuncs::writeHeaders);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, headers);
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, json_object_get_string(post));
int error = curl_easy_perform(curl);
std::string location = curlFuncs::getHeader("Location", headers);
if (error == CURLE_OK && location != HEADER_ERROR)
{
CURL *curlUp = curl_easy_init();
curl_easy_setopt(curlUp, CURLOPT_PUT, 1);
curl_easy_setopt(curlUp, CURLOPT_URL, location.c_str());
curl_easy_setopt(curlUp, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
curl_easy_setopt(curlUp, CURLOPT_WRITEDATA, jsonResp);
curl_easy_setopt(curlUp, CURLOPT_READFUNCTION, curlFuncs::readDataFile);
curl_easy_setopt(curlUp, CURLOPT_READDATA, _upload);
curl_easy_setopt(curlUp, CURLOPT_UPLOAD_BUFFERSIZE, DRIVE_UPLOAD_BUFFER_SIZE);
curl_easy_setopt(curlUp, CURLOPT_UPLOAD, 1);
curl_easy_perform(curlUp);
curl_easy_cleanup(curlUp);
json_object *parse = json_tokener_parse(jsonResp->c_str()), *id, *name, *mimeType;
json_object_object_get_ex(parse, "id", &id);
json_object_object_get_ex(parse, "name", &name);
json_object_object_get_ex(parse, "mimeType", &mimeType);
if(name && id && mimeType)
{
drive::gdDirItem uploadData;
uploadData.id = json_object_get_string(id);
uploadData.name = json_object_get_string(name);
uploadData.mimeType = json_object_get_string(mimeType);
uploadData.size = *_upload->o;//should be safe to use
uploadData.parents.push_back(parentDir);
driveList.push_back(uploadData);
}
}
else
writeCurlError("uploadFile", error);
delete jsonResp;
delete headers;
json_object_put(post);
curl_slist_free_all(postHeaders);
}
void drive::gd::updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload)
{
if(!tokenIsValid())
refreshToken();
//URL
std::string url = driveUploadURL;
url.append("/" + _fileID);
url.append("?uploadType=resumable");
//Header
curl_slist *patchHeader = NULL;
patchHeader = curl_slist_append(patchHeader, std::string(HEADER_AUTHORIZATION + token).c_str());
//Curl
std::string *jsonResp = new std::string;
std::vector<std::string> *headers = new std::vector<std::string>;
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PATCH");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, patchHeader);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, curlFuncs::writeDataString);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, curlFuncs::writeHeaders);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, jsonResp);
curl_easy_setopt(curl, CURLOPT_HEADERDATA, headers);
int error = curl_easy_perform(curl);
std::string location = curlFuncs::getHeader("Location", headers);
if(error == CURLE_OK && location != HEADER_ERROR)
{
CURL *curlPatch = curl_easy_init();
curl_easy_setopt(curlPatch, CURLOPT_PUT, 1);
curl_easy_setopt(curlPatch, CURLOPT_URL, location.c_str());
curl_easy_setopt(curlPatch, CURLOPT_READFUNCTION, curlFuncs::readDataFile);
curl_easy_setopt(curlPatch, CURLOPT_READDATA, _upload);
curl_easy_setopt(curlPatch, CURLOPT_UPLOAD_BUFFERSIZE, DRIVE_UPLOAD_BUFFER_SIZE);
curl_easy_setopt(curlPatch, CURLOPT_UPLOAD, 1);
curl_easy_perform(curlPatch);
curl_easy_cleanup(curlPatch);
}
delete jsonResp;
delete headers;
curl_slist_free_all(patchHeader);
curl_easy_cleanup(curl);
}
void drive::gd::downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download)
{
if(!tokenIsValid())
refreshToken();
//URL
std::string url = driveURL;
url.append("/" + _fileID);
url.append("?alt=media");
//Headers
curl_slist *getHeaders = NULL;
getHeaders = curl_slist_append(getHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
//Downloading is threaded because it's too slow otherwise
dlWriteThreadStruct dlWrite;
dlWrite.cfa = _download;
Thread writeThread;
threadCreate(&writeThread, writeThread_t, &dlWrite, NULL, 0x8000, 0x2B, 2);
//Curl
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, getHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeDataBufferThreaded);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dlWrite);
threadStart(&writeThread);
int error = curl_easy_perform(curl);
threadWaitForExit(&writeThread);
threadClose(&writeThread);
curl_slist_free_all(getHeaders);
curl_easy_cleanup(curl);
}
void drive::gd::deleteFile(const std::string& _fileID)
{
if(!tokenIsValid())
refreshToken();
//URL
std::string url = driveURL;
url.append("/" + _fileID);
//Header
curl_slist *delHeaders = NULL;
delHeaders = curl_slist_append(delHeaders, std::string(HEADER_AUTHORIZATION + token).c_str());
//Curl
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_easy_setopt(curl, CURLOPT_USERAGENT, userAgent);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, delHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
int error = curl_easy_perform(curl);
curl_slist_free_all(delHeaders);
curl_easy_cleanup(curl);
}
std::string drive::gd::getFileID(const std::string& _name)
{
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].name == _name)
return driveList[i].id;
}
return "";
}

View File

@ -31,8 +31,6 @@ static const uint32_t blueMask = 0x0000FF00;
static const uint32_t alphaMask = 0x000000FF;
static const uint32_t breakPoints[7] = {' ', L' ', '/', '_', '-', L'', L''};
static uint8_t *alphaMod;
static inline bool compClr(const SDL_Color *c1, const SDL_Color *c2)
{
return (c1->r == c2->r) && (c1->b == c2->b) && (c1->g == c2->g) && (c1->a == c2->a);
@ -104,12 +102,6 @@ void gfx::init()
SDL_SetRenderDrawBlendMode(render, SDL_BLENDMODE_BLEND);
//Load the alpha mod to round icon corners
alphaMod = (uint8_t *)malloc(256 * 256);
FILE *modLoad = fopen("romfs:/img/icn/icon.msk", "rb");
fread(alphaMod, 1, 256 * 256, modLoad);
fclose(modLoad);
loadSystemFont();
}
@ -119,8 +111,6 @@ void gfx::exit()
SDL_Quit();
freeSystemFont();
free(alphaMod);
for(auto c : glyphCache)
SDL_DestroyTexture(c.second.tex);
}

View File

@ -1,4 +1,5 @@
#include <switch.h>
#include <curl/curl.h>
#include "gfx.h"
#include "file.h"
@ -49,8 +50,14 @@ int main(int argc, const char *argv[])
ui::init();
romfsExit();
curl_global_init(CURL_GLOBAL_ALL);
//Drive needs config read
fs::driveInit();
while(ui::runApp()){ }
fs::driveExit();
curl_global_cleanup();
cfg::saveConfig();
ui::exit();
data::exit();

View File

@ -149,6 +149,7 @@ void ui::init()
ui::settInit();
ui::extInit();
ui::fmInit();
ui::fldInit();
popMessages = new ui::popMessageMngr;
threadMngr = new ui::threadProcMngr;
@ -165,6 +166,7 @@ void ui::exit()
ui::settExit();
ui::extExit();
ui::fmExit();
ui::fldExit();
delete popMessages;
delete threadMngr;
@ -312,7 +314,7 @@ void ui::toTTL(void *a)
if(u->titleInfo.size() > 0)
{
ui::changeState(TTL_SEL);
ui::ttlSetActive(curUserIndex);
ui::ttlSetActive(curUserIndex, true, true);
ui::usrMenu->setActive(false);
}
else

View File

@ -28,7 +28,7 @@ static inline void closeUserPanel()
static void toFMSDtoSD(void *a)
{
ui::fmPrep(FsSaveDataType_Account, "sdmc:/", false);
ui::fmPrep(FsSaveDataType_Account, "sdmc:/", "sdmc:/", false);
closeUserPanel();
ui::changeState(FIL_MDE);
}
@ -39,7 +39,7 @@ static void toFMProdInfoF(void *a)
fsOpenBisFileSystem(&prodf, FsBisPartitionId_CalibrationFile, "");
fsdevMountDevice("prod-f", prodf);
closeUserPanel();
ui::fmPrep(FsSaveDataType_System, "prod-f:/", false);
ui::fmPrep(FsSaveDataType_System, "prod-f:/", "sdmc:/", false);
ui::changeState(FIL_MDE);
}
@ -49,7 +49,7 @@ static void toFMSafe(void *a)
fsOpenBisFileSystem(&safe, FsBisPartitionId_SafeMode, "");
fsdevMountDevice("safe", safe);
closeUserPanel();
ui::fmPrep(FsSaveDataType_System, "safe:/", false);
ui::fmPrep(FsSaveDataType_System, "safe:/", "sdmc:/", false);
ui::changeState(FIL_MDE);
}
@ -59,7 +59,7 @@ static void toFMSystem(void *a)
fsOpenBisFileSystem(&sys, FsBisPartitionId_System, "");
fsdevMountDevice("sys", sys);
closeUserPanel();
ui::fmPrep(FsSaveDataType_System, "sys:/", false);
ui::fmPrep(FsSaveDataType_System, "sys:/", "sdmc:/", false);
ui::changeState(FIL_MDE);
}
@ -69,7 +69,7 @@ static void toFMUser(void *a)
fsOpenBisFileSystem(&user, FsBisPartitionId_User, "");
fsdevMountDevice("user", user);
closeUserPanel();
ui::fmPrep(FsSaveDataType_System, "user:/", false);
ui::fmPrep(FsSaveDataType_System, "user:/", "sdmc:/", false);
ui::changeState(FIL_MDE);
}
@ -109,7 +109,7 @@ static void extMenuMountSysSave(void *a)
if(R_SUCCEEDED(fsOpen_SystemSaveData(&sys, FsSaveDataSpaceId_System, mountID, (AccountUid) {0})))
{
fsdevMountDevice("sv", sys);
ui::fmPrep(FsSaveDataType_System, "sv:/", true);
ui::fmPrep(FsSaveDataType_System, "sv:/", "sdmc:/", true);
ui::usrSelPanel->closePanel();
ui::changeState(FIL_MDE);
}
@ -129,8 +129,8 @@ static void extMenuMountRomFS(void *a)
if(R_SUCCEEDED(fsOpenDataFileSystemByCurrentProcess(&tromfs)))
{
fsdevMountDevice("tromfs", tromfs);
ui::fmPrep(FsSaveDataType_System, "tromfs:/", false);
ui::usrSelPanel->closePanel();
ui::fmPrep(FsSaveDataType_System, "tromfs:/", "sdmc:/", false);
ui::usrSelPanel->closePanel();
ui::changeState(FIL_MDE);
}
}
@ -142,7 +142,7 @@ static void extMenuPackJKSVZip_t(void *a)
t->status->setStatus(ui::getUICString("threadStatusPackingJKSV", 0));
if(cfg::config["ovrClk"])
{
util::setCPU(util::CPU_SPEED_1785MHz);
util::sysBoost();
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popCPUBoostEnabled", 0));
}
@ -164,7 +164,7 @@ static void extMenuPackJKSVZip_t(void *a)
zipClose(zip, NULL);
}
if(cfg::config["ovrClk"])
util::setCPU(util::CPU_SPEED_1224MHz);
util::sysNormal();
delete jksv;
delete c;

404
src/ui/fld.cpp Normal file
View File

@ -0,0 +1,404 @@
#include <switch.h>
#include "ui.h"
#include "fs.h"
#include "util.h"
#include "cfg.h"
static ui::menu *fldMenu = NULL;
ui::slideOutPanel *ui::fldPanel = NULL;
static fs::dirList *fldList = NULL;
static SDL_Texture *fldBuffer;
static unsigned int fldGuideWidth = 0;
static Mutex fldLock = 0;
static void fldMenuCallback(void *a)
{
switch(ui::padKeysDown())
{
case HidNpadButton_B:
if(fs::gDrive)
fs::gDrive->returnToRoot();
fs::unmountSave();
fs::freePathFilters();
fldMenu->setActive(false);
ui::fldPanel->closePanel();
unsigned cusr = data::getCurrentUserIndex();
ui::ttlSetActive(cusr, true, true);
ui::updateInput();
break;
}
}
static void fldPanelDraw(void *a)
{
mutexLock(&fldLock);
SDL_Texture *target = (SDL_Texture *)a;
gfx::clearTarget(fldBuffer, &ui::slidePanelColor);
fldMenu->draw(fldBuffer, &ui::txtCont, true);
gfx::texDraw(target, fldBuffer, 0, 0);
gfx::drawLine(target, &ui::divClr, 10, 648, fldGuideWidth + 54, 648);
gfx::drawTextf(target, 18, 32, 673, &ui::txtCont, ui::getUICString("helpFolder", 0));
mutexUnlock(&fldLock);
}
static void fldFuncCancel(void *a)
{
std::string *del = (std::string *)a;
delete del;
}
static void fldFuncOverwrite(void *a)
{
fs::dirItem *in = (fs::dirItem *)a;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
std::string *send = new std::string;
send->assign(util::generatePathByTID(utinfo->tid) + in->getItm());
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, fldFuncCancel, send, ui::getUICString("confirmOverwrite", 0), in->getItm().c_str());
ui::confirm(conf);
}
static void fldFuncDelete(void *a)
{
fs::dirItem *in = (fs::dirItem *)a;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
std::string *send = new std::string;
send->assign(util::generatePathByTID(utinfo->tid) + in->getItm());
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, fldFuncCancel, send, ui::getUICString("confirmDelete", 0), in->getItm().c_str());
ui::confirm(conf);
}
static void fldFuncRestore(void *a)
{
fs::dirItem *in = (fs::dirItem *)a;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
std::string *send = new std::string;
send->assign(util::generatePathByTID(utinfo->tid) + in->getItm());
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, fldFuncCancel, send, ui::getUICString("confirmRestore", 0), in->getItm().c_str());
ui::confirm(conf);
}
static void fldFuncUpload_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::dirItem *di = (fs::dirItem *)t->argPtr;
fsSetPriority(FsPriority_Realtime);
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
std::string path, tmpZip, filename;//Final path to upload from
if(cfg::config["ovrClk"])
util::sysBoost();
//Zip first then upload if folder based backup
if(di->isDir())
{
t->status->setStatus(ui::getUICString("threadStatusCompressingSaveForUpload", 0), di->getItm().c_str());
filename = di->getItm() + ".zip";
tmpZip = util::generatePathByTID(utinfo->tid) + di->getItm() + ".zip";
std::string fldPath = util::generatePathByTID(utinfo->tid) + di->getItm() + "/";
int zipTrim = util::getTotalPlacesInPath(fs::getWorkDir()) + 2;//Trim path down to save root
zipFile tmp = zipOpen64(tmpZip.c_str(), 0);
fs::copyDirToZip(fldPath, tmp, true, zipTrim, NULL);
zipClose(tmp, NULL);
path = tmpZip;
}
else
{
filename = di->getItm();
path = util::generatePathByTID(utinfo->tid) + di->getItm();
}
//Change thread stuff so upload status can be shown
t->status->setStatus(ui::getUICString("threadStatusUploadingFile", 0), di->getItm().c_str());
fs::copyArgs *cpyArgs = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
cpyArgs->prog->setMax(fs::fsize(path));
cpyArgs->prog->update(0);
t->argPtr = cpyArgs;
t->drawFunc = fs::fileDrawFunc;
//curlDlArgs
curlFuncs::curlUpArgs upload;
upload.f = fopen(path.c_str(), "rb");
upload.o = &cpyArgs->offset;
if(fs::gDrive->fileExists(filename))
{
std::string id = fs::gDrive->getFileID(filename);
fs::gDrive->updateFile(id, &upload);
}
else
fs::gDrive->uploadFile(filename, &upload);
fclose(upload.f);
if(!tmpZip.empty())
fs::delfile(tmpZip);
fs::copyArgsDestroy(cpyArgs);
t->drawFunc = NULL;
if(cfg::config["ovrClk"])
util::sysNormal();
ui::fldRefreshMenu(false);
t->finished = true;
}
static void fldFuncUpload(void *a)
{
if(fs::gDrive)
ui::newThread(fldFuncUpload_t, a, NULL);
else
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveNotActive", 0));
}
static void fldFuncDownload_t(void *a)
{
threadInfo *t = (threadInfo *)a;
drive::gdDirItem *in = (drive::gdDirItem *)t->argPtr;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
std::string targetPath = util::generatePathByTID(utinfo->tid) + in->name;
t->status->setStatus(ui::getUICString("threadStatusDownloadingFile", 0), in->name.c_str());
if(cfg::config["ovrClk"])
util::sysBoost();
if(fs::fileExists(targetPath))
fs::delfile(targetPath);
//Use this for progress bar
fs::copyArgs *cpy = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
cpy->prog->setMax(in->size);
cpy->prog->update(0);
t->argPtr = cpy;
t->drawFunc = fs::fileDrawFunc;
//DL struct
curlFuncs::curlDlArgs dlFile;
dlFile.path = targetPath;
dlFile.size = in->size;
dlFile.o = &cpy->offset;
fs::gDrive->downloadFile(in->id, &dlFile);
//fclose(dlFile.f);
fs::copyArgsDestroy(cpy);
t->drawFunc = NULL;
if(cfg::config["ovrClk"])
util::sysNormal();
ui::fldRefreshMenu(false);
t->finished = true;
}
static void fldFuncDownload(void *a)
{
drive::gdDirItem *in = (drive::gdDirItem *)a;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
std::string testPath = util::generatePathByTID(utinfo->tid) + in->name;
if(fs::fileExists(testPath))
{
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fldFuncDownload_t, NULL, a, ui::getUICString("confirmDriveOverwrite", 0));
ui::confirm(conf);
}
else
ui::newThread(fldFuncDownload_t, a, NULL);
}
static void fldFuncDriveDelete_t(void *a)
{
threadInfo *t = (threadInfo *)a;
drive::gdDirItem *gdi = (drive::gdDirItem *)t->argPtr;
t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0));
fs::gDrive->deleteFile(gdi->id);
ui::fldRefreshMenu(true);
t->finished = true;
}
static void fldFuncDriveDelete(void *a)
{
drive::gdDirItem *in = (drive::gdDirItem *)a;
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fldFuncDriveDelete_t, NULL, a, ui::getUICString("confirmDelete", 0), in->name.c_str());
ui::confirm(conf);
}
//TODO
static void fldFuncDriveRestore_t(void *a)
{
threadInfo *t = (threadInfo *)a;
drive::gdDirItem *gdi = (drive::gdDirItem *)t->argPtr;
t->status->setStatus(ui::getUICString("threadStatusDownloadingFile", 0), gdi->name.c_str());
fs::copyArgs *cpy = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
cpy->prog->setMax(gdi->size);
cpy->prog->update(0);
t->argPtr = cpy;
t->drawFunc = fs::fileDrawFunc;
curlFuncs::curlDlArgs dlFile;
dlFile.path = "sdmc:/tmp.zip";
dlFile.size = gdi->size;
dlFile.o = &cpy->offset;
fs::gDrive->downloadFile(gdi->id, &dlFile);
unzFile tmp = unzOpen64("sdmc:/tmp.zip");
fs::copyZipToDir(tmp, "sv:/", "sv", t);
unzClose(tmp);
fs::delfile("sdmc:/tmp.zip");
fs::copyArgsDestroy(cpy);
t->argPtr = NULL;
t->drawFunc = NULL;
t->finished = true;
}
static void fldFuncDriveRestore(void *a)
{
drive::gdDirItem *in = (drive::gdDirItem *)a;
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fldFuncDriveRestore_t, NULL, a, ui::getUICString("confirmRestore", 0), in->name.c_str());
ui::confirm(conf);
}
void ui::fldInit()
{
fldGuideWidth = gfx::getTextWidth(ui::getUICString("helpFolder", 0), 18);
fldMenu = new ui::menu(10, 8, fldGuideWidth + 44, 20, 6);
fldMenu->setCallback(fldMenuCallback, NULL);
fldMenu->setActive(false);
ui::fldPanel = new ui::slideOutPanel(fldGuideWidth + 64, 720, 0, ui::SLD_RIGHT, fldPanelDraw);
fldBuffer = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, fldGuideWidth + 64, 647);
ui::registerPanel(fldPanel);
fldList = new fs::dirList;
}
void ui::fldExit()
{
delete ui::fldPanel;
delete fldMenu;
delete fldList;
SDL_DestroyTexture(fldBuffer);
}
void ui::fldUpdate()
{
fldMenu->update();
}
void ui::fldPopulateMenu()
{
mutexLock(&fldLock);
fldMenu->reset();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
data::titleInfo *t = data::getTitleInfoByTID(d->tid);
util::createTitleDirectoryByTID(d->tid);
std::string targetDir = util::generatePathByTID(d->tid);
fldList->reassign(targetDir);
if(fs::gDrive)
{
if(!fs::gDrive->dirExists(t->title))
fs::gDrive->createDir(t->title);
std::string dirID = fs::gDrive->getFileID(t->title);
fs::gDrive->chDir(dirID);
}
fs::loadPathFilters(d->tid);
fldMenu->addOpt(NULL, ui::getUICString("folderMenuNew", 0));
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL);
unsigned fldInd = 1;
if(fs::gDrive && fs::gDrive->getDriveListCount() > 0)
{
for(unsigned i = 0; i < fs::gDrive->getDriveListCount(); i++, fldInd++)
{
drive::gdDirItem *gdi = fs::gDrive->getDirItemAt(i);
fldMenu->addOpt(NULL, "[GD] " + gdi->name);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, gdi);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, gdi);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncDriveRestore, gdi);
}
}
for(unsigned i = 0; i < fldList->getCount(); i++, fldInd++)
{
fs::dirItem *di = fldList->getDirItemAt(i);
fldMenu->addOpt(NULL, di->getItm());
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncOverwrite, di);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDelete, di);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncRestore, di);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_ZR, fldFuncUpload, di);
}
fldMenu->setActive(true);
ui::fldPanel->openPanel();
mutexUnlock(&fldLock);
}
void ui::fldRefreshMenu(bool _updateDrive)
{
mutexLock(&fldLock);
fldMenu->reset();
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
data::titleInfo *tinfo = data::getTitleInfoByTID(utinfo->tid);
std::string targetDir = util::generatePathByTID(utinfo->tid);
fldList->reassign(targetDir);
if(_updateDrive && fs::gDrive)
fs::gDrive->loadDriveList("");
fldMenu->addOpt(NULL, ui::getUIString("folderMenuNew", 0));
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL);
unsigned fldInd = 1;
if(fs::gDrive && fs::gDrive->getDriveListCount() > 0)
{
for(unsigned i = 0; i < fs::gDrive->getDriveListCount(); i++, fldInd++)
{
drive::gdDirItem *gdi = fs::gDrive->getDirItemAt(i);
fldMenu->addOpt(NULL, "[GD] " + gdi->name);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncDownload, gdi);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDriveDelete, gdi);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncDriveRestore, gdi);
}
}
for(unsigned i = 0; i < fldList->getCount(); i++, fldInd++)
{
fs::dirItem *di = fldList->getDirItemAt(i);
fldMenu->addOpt(NULL, di->getItm());
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_A, fldFuncOverwrite, di);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_X, fldFuncDelete, di);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_Y, fldFuncRestore, di);
fldMenu->optAddButtonEvent(fldInd, HidNpadButton_ZR, fldFuncUpload, di);
}
mutexUnlock(&fldLock);
}

View File

@ -514,13 +514,13 @@ void ui::fmExit()
delete sdmcArgs;
}
void ui::fmPrep(const FsSaveDataType& _type, const std::string& _dev, bool _commit)
void ui::fmPrep(const FsSaveDataType& _type, const std::string& _dev, const std::string& _baseSDMC, bool _commit)
{
type = _type;
dev = _dev;
commit = _commit;
devPath = _dev;
sdPath = "sdmc:/";
sdPath = _baseSDMC;
sdCopyMenu->editOpt(0, NULL, ui::getUIString("fileModeMenu", 0) + _dev);

View File

@ -56,7 +56,7 @@ static void settMenuDeleteAllBackups_t(void *a)
fs::dirList *jksvDir = new fs::dirList(fs::getWorkDir());
for(unsigned i = 0; i < jksvDir->getCount(); i++)
{
if(jksvDir->isDir(i))
if(jksvDir->isDir(i) && jksvDir->getItem(i) != "svi")
{
std::string delTarget = fs::getWorkDir() + jksvDir->getItem(i) + "/";
fs::delDir(delTarget);

View File

@ -6,90 +6,19 @@
#include "util.h"
#include "cfg.h"
static int ttlHelpX = 0, fldHelpWidth = 0;
static int ttlHelpX = 0;
static std::vector<ui::titleview *> ttlViews;
static ui::menu *ttlOpts, *fldMenu;
static ui::menu *ttlOpts;
ui::slideOutPanel *ui::ttlOptsPanel;
static ui::slideOutPanel *infoPanel, *fldPanel;//There's no reason to have a separate folder section
static fs::dirList *fldList;
static std::string infoPanelString;
static SDL_Texture *fldBuffer;//This is so folder menu doesn't draw over guide
static ui::slideOutPanel *infoPanel;
static Mutex ttlViewLock = 0;
void ui::ttlRefresh()
{
mutexLock(&ttlViewLock);
for(int i = 0; i < (int)data::users.size(); i++)
ttlViews[i]->refresh();
}
static void fldFuncCancel(void *a)
{
std::string *del = (std::string *)a;
delete del;
}
static void fldFuncOverwrite(void *a)
{
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
int sel = fldMenu->getSelected() - 1;//Skip 'New'
std::string itm = fldList->getItem(sel);
std::string *send = new std::string;
send->assign(util::generatePathByTID(utinfo->tid) + itm);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdOver"], fs::overwriteBackup, fldFuncCancel, send, ui::getUICString("confirmOverwrite", 0), itm.c_str());
ui::confirm(conf);
}
static void fldFuncDelete(void *a)
{
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
int sel = fldMenu->getSelected() - 1;//Skip 'New'
std::string itm = fldList->getItem(sel);
std::string *send = new std::string;
send->assign(util::generatePathByTID(utinfo->tid) + itm);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdDel"], fs::deleteBackup, fldFuncCancel, send, ui::getUICString("confirmDelete", 0), itm.c_str());
ui::confirm(conf);
}
static void fldFuncRestore(void *a)
{
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
int sel = fldMenu->getSelected() - 1;//Skip 'New'
std::string itm = fldList->getItem(sel);
std::string *send = new std::string;
send->assign(util::generatePathByTID(utinfo->tid) + itm);
ui::confirmArgs *conf = ui::confirmArgsCreate(cfg::config["holdRest"], fs::restoreBackup, fldFuncCancel, send, ui::getUICString("confirmRestore", 0), itm.c_str());
ui::confirm(conf);
}
void ui::populateFldMenu()
{
fldMenu->reset();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
util::createTitleDirectoryByTID(d->tid);
std::string targetDir = util::generatePathByTID(d->tid);
fldList->reassign(targetDir);
char filterPath[128];
sprintf(filterPath, "sdmc:/config/JKSV/0x%016lX_filter.txt", d->tid);
fs::loadPathFilters(d->tid);
fldMenu->addOpt(NULL, ui::getUICString("folderMenuNew", 0));
fldMenu->optAddButtonEvent(0, HidNpadButton_A, fs::createNewBackup, NULL);
for(unsigned i = 0; i < fldList->getCount(); i++)
{
fldMenu->addOpt(NULL, fldList->getItem(i));
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_A, fldFuncOverwrite, NULL);
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_X, fldFuncDelete, NULL);
fldMenu->optAddButtonEvent(i + 1, HidNpadButton_Y, fldFuncRestore, NULL);
}
fldMenu->setActive(true);
fldPanel->openPanel();
mutexUnlock(&ttlViewLock);
}
static void ttlViewCallback(void *a)
@ -104,7 +33,10 @@ static void ttlViewCallback(void *a)
{
case HidNpadButton_A:
if(fs::mountSave(d->saveInfo))
ui::populateFldMenu();
{
ttlViews[curUserIndex]->setActive(false, true);
ui::fldPopulateMenu();
}
break;
case HidNpadButton_B:
@ -195,7 +127,9 @@ static void ttlOptsToFileMode(void *a)
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
if(fs::mountSave(d->saveInfo))
{
ui::fmPrep((FsSaveDataType)d->saveInfo.save_data_type, "sv:/", true);
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
std::string sdmcPath = util::generatePathByTID(utinfo->tid);
ui::fmPrep((FsSaveDataType)d->saveInfo.save_data_type, "sv:/", sdmcPath, true);
ui::usrSelPanel->closePanel();
ui::ttlOptsPanel->closePanel();
ui::changeState(FIL_MDE);
@ -308,6 +242,31 @@ static void ttlOptsExtendSaveData(void *a)
}
}
static void ttlOptsExportSVI(void *a)
{
data::userTitleInfo *ut = data::getCurrentUserTitleInfo();
data::titleInfo *t = data::getTitleInfoByTID(ut->tid);
std::string out = fs::getWorkDir() + "svi/";
fs::mkDir(out.substr(0, out.length() - 1));
out += util::getIDStr(ut->tid) + ".svi";
FILE *svi = fopen(out.c_str(), "wb");
if(svi)
{
//Grab icon
NsApplicationControlData *ctrlData = new NsApplicationControlData;
uint64_t ctrlSize = 0;
nsGetApplicationControlData(NsApplicationControlSource_Storage, ut->tid, ctrlData, sizeof(NsApplicationControlData), &ctrlSize);
size_t jpegSize = ctrlSize - sizeof(ctrlData->nacp);
fwrite(&ut->tid, sizeof(uint64_t), 1, svi);
fwrite(&t->nacp, sizeof(NacpStruct), 1, svi);
fwrite(ctrlData->icon, 1, jpegSize, svi);
fclose(svi);
delete ctrlData;
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popSVIExported", 0));
}
}
static void infoPanelDraw(void *a)
{
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
@ -376,34 +335,9 @@ static void infoPanelCallback(void *a)
}
}
static void fldMenuCallback(void *a)
{
switch(ui::padKeysDown())
{
case HidNpadButton_B:
fs::unmountSave();
fs::freePathFilters();
fldMenu->setActive(false);
fldPanel->closePanel();
break;
}
ui::updateInput();
}
static void fldPanelDraw(void *a)
{
SDL_Texture *target = (SDL_Texture *)a;
gfx::clearTarget(fldBuffer, &ui::slidePanelColor);
fldMenu->draw(fldBuffer, &ui::txtCont, true);
gfx::texDraw(target, fldBuffer, 0, 0);
gfx::drawLine(target, &ui::divClr, 10, 648, fldHelpWidth + 54, 648);
gfx::drawTextf(target, 18, 32, 673, &ui::txtCont, ui::getUICString("helpFolder", 0));
}
void ui::ttlInit()
{
ttlHelpX = 1220 - gfx::getTextWidth(ui::getUICString("helpTitle", 0), 18);
fldHelpWidth = gfx::getTextWidth(ui::getUICString("helpFolder", 0), 18);
for(data::user& u : data::users)
ttlViews.emplace_back(new ui::titleview(u, 128, 128, 16, 16, 7, ttlViewCallback));
@ -412,10 +346,6 @@ void ui::ttlInit()
ttlOpts->setCallback(ttlOptsCallback, NULL);
ttlOpts->setActive(false);
fldMenu = new ui::menu(10, 8, fldHelpWidth + 44, 20, 6);
fldMenu->setCallback(fldMenuCallback, NULL);
fldMenu->setActive(false);
ttlOptsPanel = new ui::slideOutPanel(410, 720, 0, ui::SLD_RIGHT, ttlOptsPanelDraw);
ui::registerPanel(ttlOptsPanel);
@ -423,14 +353,8 @@ void ui::ttlInit()
ui::registerPanel(infoPanel);
infoPanel->setCallback(infoPanelCallback, NULL);
fldPanel = new ui::slideOutPanel(fldHelpWidth + 64, 720, 0, ui::SLD_RIGHT, fldPanelDraw);
fldBuffer = SDL_CreateTexture(gfx::render, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC | SDL_TEXTUREACCESS_TARGET, fldHelpWidth + 64, 647);
ui::registerPanel(fldPanel);
fldList = new fs::dirList;
ttlOpts->setActive(false);
for(int i = 0; i < 8; i++)
for(int i = 0; i < 9; i++)
ttlOpts->addOpt(NULL, ui::getUIString("titleOptions", i));
//Information
@ -449,25 +373,23 @@ void ui::ttlInit()
ttlOpts->optAddButtonEvent(6, HidNpadButton_A, ttlOptsDeleteSaveData, NULL);
//Extend
ttlOpts->optAddButtonEvent(7, HidNpadButton_A, ttlOptsExtendSaveData, NULL);
//Export NACP
ttlOpts->optAddButtonEvent(8, HidNpadButton_A, ttlOptsExportSVI, NULL);
}
void ui::ttlExit()
{
for(ui::titleview *t : ttlViews)
delete t;
SDL_DestroyTexture(fldBuffer);
delete ttlOptsPanel;
delete ttlOpts;
delete infoPanel;
delete fldPanel;
delete fldMenu;
delete fldList;
}
void ui::ttlSetActive(int usr)
void ui::ttlSetActive(int usr, bool _set, bool _showSel)
{
ttlViews[usr]->setActive(true, true);
ttlViews[usr]->setActive(_set, _showSel);
}
void ui::ttlUpdate()
@ -476,7 +398,7 @@ void ui::ttlUpdate()
ttlOpts->update();
infoPanel->update();
fldMenu->update();
ui::fldUpdate();
ttlViews[curUserIndex]->update();
}
@ -484,7 +406,9 @@ void ui::ttlDraw(SDL_Texture *target)
{
unsigned curUserIndex = data::getCurrentUserIndex();
mutexLock(&ttlViewLock);
ttlViews[curUserIndex]->draw(target);
mutexUnlock(&ttlViewLock);
if(ui::mstate == TTL_SEL && !fldPanel->isOpen())
gfx::drawTextf(NULL, 18, ttlHelpX, 673, &ui::txtCont, ui::getUICString("helpTitle", 0));
}

View File

@ -108,7 +108,7 @@ void ui::initStrings()
addUIString("author", 0, "NULL");
addUIString("helpUser", 0, "[A] Select [Y] Dump All Saves [X] User Options");
addUIString("helpTitle", 0, "[A] Select [L][R] Jump [Y] Favorite [X] Title Options [B] Back");
addUIString("helpFolder", 0, "[A] Select [Y] Restore [X] Delete [B] Close");
addUIString("helpFolder", 0, "[A] Select [Y] Restore [X] Delete [ZR] Upload [B] Close");
addUIString("helpSettings", 0, "[A] Toggle [X] Defaults [B] Back");
//Y/N On/Off
@ -132,6 +132,7 @@ void ui::initStrings()
addUIString("confirmCreateAllSaveData", 0, "Are you sure you would like to create all save data on this system for #%s#? This can take a while depending on how many titles are found.");
addUIString("confirmDeleteBackupsTitle", 0, "Are you sure you would like to delete all save backups for #%s#?");
addUIString("confirmDeleteBackupsAll", 0, "Are you sure you would like to delete *all* of your save backups for all of your games?");
addUIString("confirmDriveOverwrite", 0, "Downloading this backup from drive will overwrite the one on your SD card. Continue?");
//Save Data related strings
addUIString("saveDataNoneFound", 0, "No saves found for #%s#!");
@ -246,6 +247,7 @@ void ui::initStrings()
addUIString("titleOptions", 5, "Reset Save Data");
addUIString("titleOptions", 6, "Delete Save Data");
addUIString("titleOptions", 7, "Extend Save Data");
addUIString("titleOptions", 8, "Export SVI");
//Thread Status Strings
addUIString("threadStatusCreatingSaveData", 0, "Creating save data for #%s#...");
@ -265,6 +267,9 @@ void ui::initStrings()
addUIString("threadStatusPackingJKSV", 0, "Writing JKSV folder contents to ZIP...");
addUIString("threadStatusSavingTranslations", 0, "Saving the file master...");
addUIString("threadStatusCalculatingSaveSize", 0, "Calculating save data size...");
addUIString("threadStatusUploadingFile", 0, "Uploading #%s#...");
addUIString("threadStatusDownloadingFile", 0, "Downloading #%s#...");
addUIString("threadStatusCompressingSaveForUpload", 0, "Compressing #%s# for upload...");
//Random leftover pop-ups
addUIString("popCPUBoostEnabled", 0, "CPU Boost Enabled for ZIP.");
@ -277,6 +282,10 @@ void ui::initStrings()
addUIString("popChangeOutputFolder", 0, "#%s# changed to #%s#");
addUIString("popChangeOutputError", 0, "#%s# contains illegal or non-ASCII characters.");
addUIString("popTrashEmptied", 0, "Trash emptied");
addUIString("popSVIExported", 0, "SVI Exported.");
addUIString("popDriveStarted", 0, "Google Drive started successfully.");
addUIString("popDriveFailed", 0, "Failed to start Google Drive.");
addUIString("popDriveNotActive", 0, "Google Drive is not available");
//Keyboard hints
addUIString("swkbdEnterName", 0, "Enter a new name");
@ -311,7 +320,7 @@ void ui::loadTrans()
std::string transTestFile = fs::getWorkDir() + "trans.txt";
std::string translationFile = "romfs:/lang/" + getFilename(data::sysLang);
bool transFile = fs::fileExists(transTestFile);
if(!transFile && (data::sysLang == SetLanguage_ENUS || cfg::config["langOverride"]))
if(!transFile && (data::sysLang == SetLanguage_ENUS || data::sysLang == SetLanguage_ENGB || cfg::config["langOverride"]))
ui::initStrings();
else if(transFile)
loadTranslationFile(transTestFile);
@ -335,9 +344,24 @@ void ui::saveTranslationFiles(void *a)
std::string outputFolder = fs::getWorkDir() + "lang", outputPath, romfsPath;
fs::mkDir(outputFolder);
//Save en-us first
ui::initStrings();
outputPath = fs::getWorkDir() + "lang/" + getFilename(SetLanguage_ENUS);
FILE *out = fopen(outputPath.c_str(), "w");
for(auto& s : ui::strings)
{
std::string stringOut = s.second;
util::replaceStr(stringOut, "\n", "\\n");
fprintf(out, "%s = %i, \"%s\"\n", s.first.first.c_str(), s.first.second, stringOut.c_str());
}
fclose(out);
romfsInit();
for(int i = 0; i < SetLanguage_Total; i++)
{
if(i == SetLanguage_ENUS)
continue;
outputPath = fs::getWorkDir() + "lang/" + getFilename(i);
romfsPath = "romfs:/lang/" + getFilename(i);
@ -345,7 +369,7 @@ void ui::saveTranslationFiles(void *a)
ui::initStrings();
loadTranslationFile(romfsPath);
FILE *out = fopen(outputPath.c_str(), "w");
out = fopen(outputPath.c_str(), "w");
for(auto& s : ui::strings)
{
std::string stringOut = s.second;

View File

@ -266,17 +266,17 @@ static void usrOptCreateAllSaves_t(void *a)
{
AccountUid uid = u->getUID();
for(unsigned i = 0; i < accSids.size(); i++)
fs::createSaveDataThreaded(FsSaveDataType_Account, accSids[i], uid);
fs::createSaveData(FsSaveDataType_Account, accSids[i], uid, t);
}
else if(sel == devPos)
{
for(unsigned i = 0; i < devSids.size(); i++)
fs::createSaveDataThreaded(FsSaveDataType_Device, devSids[i], util::u128ToAccountUID(0));
fs::createSaveData(FsSaveDataType_Device, devSids[i], util::u128ToAccountUID(0), t);
}
else if(sel == bcatPos)
{
for(unsigned i = 0; i < bcatSids.size(); i++)
fs::createSaveDataThreaded(FsSaveDataType_Bcat, bcatSids[i], util::u128ToAccountUID(0));
fs::createSaveData(FsSaveDataType_Bcat, bcatSids[i], util::u128ToAccountUID(0), t);
}
t->finished = true;
}

View File

@ -11,6 +11,7 @@
#include "ui.h"
#include "curlfuncs.h"
#include "type.h"
#include "cfg.h"
static const uint32_t verboten[] = { L',', L'/', L'\\', L'<', L'>', L':', L'"', L'|', L'?', L'*', L'', L'©', L'®'};
@ -370,23 +371,55 @@ SDL_Texture *util::createIconGeneric(const char *txt, int fontSize, bool clearBa
return ret;
}
void util::setCPU(uint32_t hz)
void util::sysBoost()
{
if(R_FAILED(clkrstInitialize()))
return;
ClkrstSession cpu;
ClkrstSession cpu, gpu, ram;
clkrstOpenSession(&cpu, PcvModuleId_CpuBus, 3);
clkrstSetClockRate(&cpu, hz);
clkrstOpenSession(&gpu, PcvModuleId_GPU, 3);
clkrstOpenSession(&ram, PcvModuleId_EMC, 3);
clkrstSetClockRate(&cpu, util::CPU_SPEED_1785MHz);
clkrstSetClockRate(&gpu, util::GPU_SPEED_76MHz);
clkrstSetClockRate(&ram, util::RAM_SPEED_1600MHz);
clkrstCloseSession(&cpu);
clkrstCloseSession(&gpu);
clkrstCloseSession(&ram);
clkrstExit();
}
void util::sysNormal()
{
if(R_FAILED(clkrstInitialize()))
return;
ClkrstSession cpu, gpu, ram;
clkrstOpenSession(&cpu, PcvModuleId_CpuBus, 3);
clkrstOpenSession(&gpu, PcvModuleId_GPU, 3);
clkrstOpenSession(&ram, PcvModuleId_EMC, 3);
if(cfg::config["ovrClk"])
clkrstSetClockRate(&cpu, util::CPU_SPEED_1224MHz);
else
clkrstSetClockRate(&cpu, util::CPU_SPEED_1020MHz);
clkrstSetClockRate(&gpu, util::GPU_SPEED_76MHz);
clkrstSetClockRate(&ram, util::RAM_SPEED_1331MHz);
clkrstCloseSession(&cpu);
clkrstCloseSession(&gpu);
clkrstCloseSession(&ram);
clkrstExit();
}
void util::checkForUpdate(void *a)
{
threadInfo *t = (threadInfo *)a;
t->status->setStatus(ui::getUICString("threadStatusCheckingForUpdate", 0));
std::string gitJson = getJSONURL(NULL, "https://api.github.com/repos/J-D-K/JKSV/releases/latest");
std::string gitJson = curlFuncs::getJSONURL(NULL, "https://api.github.com/repos/J-D-K/JKSV/releases/latest");
if(gitJson.empty())
{
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("onlineErrorConnecting", 0));
@ -412,7 +445,7 @@ void util::checkForUpdate(void *a)
std::vector<uint8_t> jksvBuff;
std::string url = json_object_get_string(dlUrl);
getBinURL(&jksvBuff, url);
curlFuncs::getBinURL(&jksvBuff, url);
FILE *jksvOut = fopen("sdmc:/switch/JKSV.nro", "wb");
fwrite(jksvBuff.data(), 1, jksvBuff.size(), jksvOut);
fclose(jksvOut);