Compare commits

..

No commits in common. "master" and "07/21/2018" have entirely different histories.

126 changed files with 3809 additions and 14010 deletions

View File

@ -1,136 +0,0 @@
---
Language: Cpp
AccessModifierOffset: -4
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Right
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: None
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: false
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: true
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: true
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Custom
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Preserve
IncludeCategories:
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
Priority: 2
SortPriority: 0
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
Priority: 3
SortPriority: 0
- Regex: '.*'
Priority: 1
SortPriority: 0
IncludeIsMainRegex: '(Test)?$'
IncludeIsMainSourceRegex: ''
IndentAccessModifiers: true
IndentCaseLabels: true
IndentGotoLabels: true
IndentPPDirectives: None
IndentWidth: 4
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 2
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Right
ReflowComments: false
SortIncludes: true
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
SpaceBeforeSquareBrackets: false
Standard: Latest
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
UseCRLF: false
UseTab: Never
...

View File

@ -1,9 +0,0 @@
---
Checks: 'clang-analyzer-*,cppcoreguidelines-*,modernize-*,bugprone-*,performance-*,readability-*,readability-non-const-parameter,misc-const-correctness,misc-use-anonymous-namespace,google-explicit-constructor,-modernize-use-trailing-return-type,-bugprone-exception-escape,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-avoid-magic-numbers,-bugprone-easily-swappable-parameters,-cppcoreguidelines-non-private-member-variables-in-classes'
WarningsAsErrors: ''
HeaderFilterRegex: ''
CheckOptions:
- key: readability-magic-numbers.IgnoredFloatingPointValues
value: '0.0;1.0;100.0;'
- key: readability-magic-numbers.IgnoredIntegerValues
value: '0;1;2;3;4;5;6;7;8;9;'

11
.gitattributes vendored
View File

@ -1,11 +0,0 @@
# Set the default behavior for all files.
* text=auto eol=lf
# Normalized and converts to native line endings on checkout.
*.c text
*.cc text
*.cxx
*.cpp text
*.h text
*.hxx text
*.hpp text

15
.gitignore vendored
View File

@ -1,16 +1,3 @@
build/
.vscode/
*.cbp
*.layout
.editorconfig
.idea/
cmake-build-debug/
# build artifacts
JKSV.elf
JKSV.lst
JKSV.nacp
JKSV.nro
JKSV.nso
JKSV.pfs0
*.layout

View File

@ -1,50 +0,0 @@
# This is mainly for IDE Support (CLION), not for building (use Makefile directly).
cmake_minimum_required(VERSION 3.8)
project(JKSV)
set(CMAKE_CXX_STANDARD 17)
set(SOURCE_FILES
src/cfg.cpp
src/curlfuncs.cpp
src/data.cpp
src/fs.cpp
src/gd.cpp
src/gfx.cpp
src/main.cpp
src/rfs.cpp
src/type.cpp
src/ui.cpp
src/util.cpp
src/webdav.cpp
src/fs/dir.cpp
src/fs/remote.cpp
src/fs/file.cpp
src/fs/fsfile.c
src/fs/zip.cpp
src/gfx/textureMgr.cpp
src/ui/ext.cpp
src/ui/fld.cpp
src/ui/fm.cpp
src/ui/miscui.cpp
src/ui/sett.cpp
src/ui/sldpanel.cpp
src/ui/thrdProc.cpp
src/ui/ttl.cpp
src/ui/ttlview.cpp
src/ui/uistr.cpp
src/ui/usr.cpp)
# Specify external includes here
include_directories(./inc)
include_directories(./inc/fs)
include_directories(./inc/gfx)
include_directories(./inc/ui)
include_directories($ENV{DEVKITPRO}/devkitA64/aarch64-none-elf/include)
include_directories($ENV{DEVKITPRO}/devkitA64/lib/gcc/aarch64-none-elf/10.1.0/include)
include_directories($ENV{DEVKITPRO}/libnx/include)
include_directories($ENV{DEVKITPRO}/portlibs/switch/include)
include_directories($ENV{DEVKITPRO}/portlibs/switch/include/freetype2)
add_executable(JKSV ${SOURCE_FILES})

View File

@ -1,42 +0,0 @@
# JKSV's Settings menu options and what they do:
1. **Empty Trash Bin**: Empties the trash folder of all backups moved to it. Running this now and then is important if you choose to use the trash bin option. It is enabled by default.
2. **Check for Updates**: Checks JKSV's Github release page for any new updates and downloads it for you.
3. **Set JKSV Output Folder**: Changes the folder in which JKSV stores your save backups. Remember to end the path with a slash so this works properly.
4. **Edit Blacklisted Titles**: Opens a menu that allows you to select and remove titles that are hidden in JKSV's title selection menu.
5. **Delete All Save Backups**: Wipes JKSV's folder clean for you to start fresh.
6. **Include Device Saves With Users**: Includes device type saves (Animal Crossing, for example) with users so finding them is easier and also makes it easier to differentiate and have multiple saves for different users on the same console.
7. **Auto Backup On Restore**: Makes JKSV automatically create a backup before restoring another backup just in case.
8. **Auto Name backups**: Automatically names backups and skips the keyboard entirely.
9. **Overclock/CPU Boost**: Overclocks the CPU when exporting ZIP archives. This has little effect on the speed of compression so it's recommended to leave it off. It's being removed in the rewrite anyway for having almost no impact.
10. **Hold to Delete**: Whether or not you would like JKSV to force you to hold A to delete a backup.
11. **Hold to Restore**: Whether or not you would like JKSV to force you to hold A to restore a backup.
12. **Hold to Overwrite**: Whether or not you would like JKSV to force you to hold A to overwrite a backup on your SD card.
13. **Force Mount**: This controls whether or not JKSV displays everything it finds on your Switch or only the saves it can successfully open and mount on boot.
14. **Account System Saves**: This controls whether or not JKSV displays system save data that has an account user ID associated with it or not. This is different than normal system save data because that does not have an account user ID associated with it.
15. **Enable Writing to System Saves**: This enables writing and restoring to system save data and writing to the BIS partitions in the file browser mode. This is **dangerous** and should normally be left off. **Any damage incurred with this option on is your own fault.**
16. **Use FS Commands Directly**: Uses the Switch's FS file functions instead of LibNX's fs_dev and stdio. This can _sometimes_ resolve odd issues.
17. **Export Saves to Zip**: Uses ZIP files for backing up saves instead of unpacked files in folders. This has the benefit of higher compatibility with various edge-case saves with non-ASCII filenames which the SD card can't handle.
18. **Force English to be Used**: Overrides the detected language and uses the default English strings.
19. **Enable Trash Bin**: Enables moving backups deleted to the `_TRASH_` folder instead of deleting them permanently.
20. **Title Sorting Type**: Changes the way titles are sorted and displayed.
22. **Animation Scale**: Changes the transition speed for animated parts of the UI. One being instant, 8.0 being the slowest _I normally allow_.

View File

@ -32,31 +32,31 @@ include $(DEVKITPRO)/libnx/switch_rules
#---------------------------------------------------------------------------------
TARGET := JKSV
BUILD := build
SOURCES := src src/ui src/fs src/gfx
SOURCES := src src/ui
DATA := data
INCLUDES := inc inc/ui inc/fs inc/gfx
INCLUDES := inc
EXEFS_SRC := exefs_src
APP_TITLE := JKSV
APP_AUTHOR := JK
APP_VERSION := 11.5.2024
APP_AUTHOR := JK_
APP_VERSION := 07/21/2018
ROMFS := romfs
ICON := icon.jpg
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -march=armv8-a+crc+crypto -mtune=cortex-a57 -mtp=soft -fPIE
ARCH := -march=armv8-a -mtune=cortex-a57 -mtp=soft -fPIE
override CFLAGS += $(INCLUDE) -D__SWITCH__
override CFLAGS += `sdl2-config --cflags` `freetype-config --cflags` `curl-config --cflags`
override CFLAGS += -g -Wall -O2 -ffunction-sections -ffast-math $(ARCH) $(DEFINES)
CFLAGS := -g -Wall -O2 -ffunction-sections \
$(ARCH) $(DEFINES)
CXXFLAGS:= $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++17
CFLAGS += $(INCLUDE) -D__SWITCH__ `freetype-config --cflags`
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11
ASFLAGS := -g $(ARCH)
LDFLAGS = -specs=$(DEVKITPRO)/libnx/switch.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map)
LIBS := `sdl2-config --libs` `freetype-config --libs` `curl-config --libs` -lSDL2_image -lwebp -lpng -ljpeg -lz -lminizip -ljson-c -ltinyxml2 -lnx
LIBS := `freetype-config --libs` -lpng -ljpeg -lnx
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
@ -160,9 +160,6 @@ clean:
send: $(BUILD)
@nxlink $(TARGET).nro
debug: $(BUILD)
@nxlink -s $(TARGET).nro
else
.PHONY: all

110
README.MD
View File

@ -1,108 +1,16 @@
# JKSV
JK's Save Manager Switch Edition.
JKSV for Switch. Mostly to get familiar with libnx. **This is still a WIP. Nothing is final yet!** **You will have to build the newer UI yourself. I'm not providing binaries until I consider it usable**
<img src="https://i.imgur.com/yLcTPzt.jpg"/>
<img src="https://dl.dropboxusercontent.com/s/wk5igkkdt89ytob/JKSV.jpg" alt="JKSV" width="240"></img>
<img src="https://dl.dropboxusercontent.com/s/xaqycf724p8ut2n/JKSV_3.jpg" alt="JKSV" width="240"></img>
<img src="https://dl.dropboxusercontent.com/s/e5qvbiz88hsrtbc/JKSV_2.jpg" alt="JKSV" width="240"></img>
## Info
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.
* 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. Upload and download save backups to [Google Drive](./REMOTE_INSTRUCTIONS.MD#gdrive) if it is configured.
8. Upload and download save backups to [WebDav](./REMOTE_INSTRUCTIONS.MD#webdav) if it is configured.
9. 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).
10. 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.
11. Extend save data containers to any size the user wants or automatically if the save cannot fit into the current one.
12. Delete save data from the system.
13. Reset save data as if the game was never launched.
14. 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.
15. 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.
16. 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.
**NOTE: Some features may require building JKSV from source. I am extremely picky and only release when I am satisfied and sure things work 100% as expected.**
## Quick Guide
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 permanent.
* Settings and Extras below.
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.
* B goes back up a folder if possible.
* X opens a small menu of options for files and directories:
* Copy to [X] - Copies the currently selected item to the location opened on the other panel. Selecting the first `.` will use the directory opened as root to copy.
* Delete deletes the currently selected item.
* Rename renames the currently selected item.
* 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
* BIS: [X] opens partition [X] in the filebrowser.
* Remove Update deletes system updates downloaded from Nintendo and asks to reboot the system to get rid of the update nag.
* Terminate Process asks for a title ID to terminate.
* Mount System Save asks for the save ID to mount. This is for when JKSV is unable to rescan with a process terminated.
* Rescan Titles reloads save data information. This can be used to reload after a process is terminated or when options are changed.
* Mount Process RomFS opens the title's romfs that is taken over to launch the homebrew menu. This only works as an NRO. The NSP will only open JKSV's own RomFS.
* Backup JKSV folder writes the entire JKSV folder to a ZIP archive and places it in your JKSV folder.
**NOTE**: Press Plus to Exit JKSV. JKSV saves all config, favorites, and the blacklist when exited. Pressing the home button and closing that way will not allow this to take place.
## Building:
# Building:
1. Requires [devkitPro](https://devkitpro.org/) and [libnx](https://github.com/switchbrew/libnx)
2. `dkp-pacman -S switch-curl switch-freetype switch-libjpeg-turbo switch-tinyxml2 switch-libjson-c switch-libpng switch-libwebp switch-sdl2 switch-sdl2_gfx switch-sdl2_image switch-zlib`
2. Requires switch-freetype, libpng, and libjpeg-turbo
## 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.
* [Iguniisu](https://github.com/igniscitrinus) for the icon.
* Uses graphics from [Twemoji](https://github.com/twitter/twemoji) covered by the [Creative Commons License](https://creativecommons.org/licenses/by/4.0/legalcode)
* [Leo](https://github.com/qazrfv1234) For the Traditional Chinese translation
* [JamePeng](https://github.com/JamePeng) For the Simplified Chinese translation.
# Credits and Thanks:
* [shared-font](https://github.com/switchbrew/switch-portlibs-examples) example by yellows8
* Authors of switch-examples for account and save mounting code.

View File

@ -1,58 +0,0 @@
# Remote Storage
⚠️ **WARNING** ⚠️: Breaking change with Version 07.27.2024. See [here](#remote-changelog)
## <a name="gdrive"></a><center> How to use Google Drive with JKSV </center>
**USING GOOGLE DRIVE WITH JKSV CURRENTLY REQUIRES BUILDING IT YOURSELF. I AM VERY BUSY LATELY AND THINGS WILL ONLY GET FINISHED WHEN I HAVE TIME. Thanks, sorry for yelling.**
**NOTE: As of Feb 2023, JKSV now uses the JSON downloaded from Google directly instead of editing JKSV's configuration file.**
**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.**
**Note: Due to Google's restrictions on unverified apps, you will be required to login once every seven days. There is nothing I can do about this at the moment.**
1. Go to https://console.cloud.google.com/cloud-resource-manager, 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/9SDS2e0.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.
5. In the top left corner of your screen, click the navigation menu to the left of where it says **Google Cloud**. Find **Enabled APIs and services**. You may need to refresh the page if it doesn't update automatically to continue. <br><center><img src="https://i.imgur.com/JhqOpgc.png" /></center>
6. **Double check at this point to make 100% sure JKSV is the active project just in case it is not.** <br><center><img src="https://i.imgur.com/U49aIcb.png" /></center>
7. Once the dashboard loads, click **+ENABLE APIS AND SERVICES**. <br><center><img src="https://i.imgur.com/qaIhjID.png" /></center>
8. Scroll down a little and find Google Drive API under Google Workspace.<br><center><img src="https://i.imgur.com/cAC7h1r.png" /></center>
9. Click on it and click Enable on the next screen.
10. 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/CRhFXQ4.png" /></center>
11. Under **Which API are you using?**, find **Cloud Storage API**. Under **What data will you be accessing?**, select **User data**. Click **Next**. <br><center><img src="https://i.imgur.com/fiulRpn.png" /></center>
12. Fill out the following screen. **Save and continue**.
13. Click **Add or Remove Scopes**.
14. Find **.../auth/drive** in the API list, select it, and click update. **Save and Continue**.
15. At this point you should be at a section named **OAuth Client ID**. Select **Desktop app**, name it **JKSV** and click **Create**.
16. Download the credentials saved in JSON format for later. Click **Done**.
17. Next, open the navigation menu in the top left again. Go down to **APIs and Services** and click on **OAuth consent screen**.<br><center><img src="https://i.imgur.com/OrMtG1x.png" /></center>
18. Scroll down to the section named **Test users**. Add yourself as a test user. This concludes the Google side of things.<br><center><img src="https://i.imgur.com/RTV2LMZ.png" /></center>
19. Next, find the JSON file you downloaded earlier. Copy it or send it via FTP to the following folder on your SD Card: `SD:/config/JKSV/`
20. The next time you start JKSV on your Switch, you should be prompted to login to Google via the Switch's web browser. Ta-da!
## <a name="webdav"></a><center> How to use WebDav with JKSV </center>
**NOTE: If you have [GDrive](#gdrive) configured (via JSON), it takes preference over WebDav**
1. Create a file `webdav.json` with the following content:
```json
{
"origin": "https://your-webdav-server",
"basepath": "optional-base-path",
"username": "testuser",
"password": "testpassword"
}
```
- `origin` (mandatory): protocol + serveraddress + (optional port), e.g. `https://your-webdav-server` or `http://localhost:8080` - **No trailing slash**
- `basepath` (optional): e.g. `dir`, `dir/subdir` must exist beforehand - **No leading AND trailing slash** - if your path uses special characters or spaces, they must be on URI encoding, by example `Game Saves` should be stored as `Game%20Saves`.
- `username` (optional): username, if server uses credentials
- `password` (optional): username, if server uses credentials
2. Copy file to following folder on your card `SD:/config/JKSV/`
3. The next time you start JKSV on your Switch, you should get a popup about the Webdav status
4. If problems arise, check the log at `SD:/JKSV/log.txt`
## Remote Changelog
- **07.27.2024**: **Breaking Change**. "Unsafe" characters were removed from titlename on the remote directory. That means,
that if you had existing safes under a title with unsafe characters, you will need to move them manually.

BIN
icon.jpg

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 110 KiB

View File

@ -1 +0,0 @@
<svg id="Layer_1" data-name="Layer 1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 967 1015"><defs><style>.cls-1{fill:#1c75bc;}.cls-2{fill:#fff;}.cls-3{fill:#231f20;}.cls-4{fill:#ed1c24;}</style></defs><path class="cls-1" d="M63.48,117.71V849.34c30.7,55.52,77.86,104.8,145.94,146.14H525.48v-961H135C92.47,41.32,69.69,70.26,63.48,117.71Z" transform="translate(-63.48 -34.48)"/><path class="cls-2" d="M525.48,564.48H264.66c-20.89,0-43.18-18.86-43.18-43.29V129.84c0-31.22,22.9-45.36,45.26-45.36H525.48Z" transform="translate(-63.48 -34.48)"/><path class="cls-3" d="M221.48,484.48v36.86c0,24.34,22.29,43.14,43.18,43.14H525.48v-80Z" transform="translate(-63.48 -34.48)"/><path class="cls-2" d="M221.48,642.52V914.43a24,24,0,0,0,24,24.05h280v-320h-280A24,24,0,0,0,221.48,642.52Zm213,270h-133v-266h133Z" transform="translate(-63.48 -34.48)"/><path class="cls-4" d="M778,84.48H622.48v965H778c139.44,0,252.49-113.05,252.49-252.49V337C1030.48,197.52,917.43,84.48,778,84.48ZM815.76,711.9a96.66,96.66,0,1,1,96.66-96.66A96.66,96.66,0,0,1,815.76,711.9Z" transform="translate(-63.48 -34.48)"/></svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,40 +0,0 @@
#pragma once
#include <cstdint>
#include <string>
#include <unordered_map>
#include <vector>
namespace cfg
{
typedef enum
{
ALPHA,
MOST_PLAYED,
LAST_PLAYED
} sortTypes;
void resetConfig();
void loadConfig();
void saveConfig();
bool isBlacklisted(uint64_t tid);
void addTitleToBlacklist(void *a);
void removeTitleFromBlacklist(uint64_t tid);
bool isFavorite(uint64_t tid);
void addTitleToFavorites(uint64_t tid);
bool isDefined(uint64_t tid);
void pathDefAdd(uint64_t tid, const std::string &newPath);
std::string getPathDefinition(uint64_t tid);
void addPathToFilter(uint64_t tid, const std::string &_p);
extern std::unordered_map<std::string, bool> config;
extern std::vector<uint64_t> blacklist;
extern std::vector<uint64_t> favorites;
extern uint8_t sortType;
extern std::string driveClientID, driveClientSecret, driveRefreshToken;
extern std::string webdavOrigin, webdavBasePath, webdavUser, webdavPassword;
} // namespace cfg

15
inc/clsui.h Normal file
View File

@ -0,0 +1,15 @@
#ifndef CLSUI_H
#define CLSUI_H
#include "data.h"
namespace ui
{
void clsUserPrep();
void clsTitlePrep(data::user& u);
void classicUserMenuUpdate(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void classicTitleMenuUpdate(const uint64_t& down, const uint64_t& held, const touchPosition& p);
}
#endif // CLSUI_H

View File

@ -1,35 +0,0 @@
#pragma once
#include <string>
#include <vector>
#define HEADER_ERROR "ERROR"
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

@ -1,131 +1,104 @@
#pragma once
#ifndef DATA_H
#define DATA_H
#include <switch.h>
#include <string>
#include <unordered_map>
#include <vector>
#include <string>
#include "gfx.h"
#define BLD_MON 5
#define BLD_DAY 28
#define BLD_YEAR 2025
namespace data
{
// Loads user + title info
void init();
extern bool sysSave;
//Loads user + title info
void loadDataInfo();
void exit();
bool loadUsersTitles(bool clearUsers);
void sortUserTitles();
// Draws some stats to the upper left corner
void dispStats();
// Global stuff for all titles/saves
typedef struct
//Class to help not load the same icons over and over
class icn
{
/// @brief Control data.
NsApplicationControlData data;
public:
//Loads jpeg icon from jpegData
void load(const uint64_t& _id, const uint8_t *jpegData, const size_t& jpegSize);
//For loading default icon
void load(const uint64_t & _id, const std::string& _png);
/// @brief Saves whether or not the title has valid control data.
bool hasControlData = false;
void draw(unsigned x, unsigned y) { texDrawNoAlpha(iconTex, texGetFramebuffer(), x, y); }
void drawHalf(unsigned x, unsigned y) { texDrawSkipNoAlpha(iconTex, texGetFramebuffer(), x, y); }
std::string title, safeTitle, author;
SDL_Texture *icon = NULL;
bool fav;
} titleInfo;
uint64_t getTitleID() { return titleID; }
// Holds stuff specific to user's titles/saves
typedef struct
void deleteData() { texDestroy(iconTex); }
private:
uint64_t titleID;
tex *iconTex;
};
//Class to store title info
class titledata
{
// Makes it easier to grab id
uint64_t tid;
FsSaveDataInfo saveInfo;
PdmPlayStatistics playStats;
} userTitleInfo;
public:
//Attempts to read title's info. Returns false if failed
bool init(const FsSaveDataInfo& inf);
// Class to store user info + titles
//Attempts to mount data with uID + id. Returns false if fails. For filtering.
bool isMountable(const u128& uID);
//Returns title + title without forbidden chars
std::string getTitle() { return title;}
std::string getTitleSafe() { return titleSafe; }
//Returns ID
uint64_t getID() { return id; }
//Game icon
icn icon;
FsSaveDataType getType() { return type; }
private:
FsSaveDataType type;
std::string title, titleSafe;
uint64_t id;
u128 uID;
};
//Class to store user info + titles
class user
{
public:
user() = default;
user(AccountUid _id, const std::string &_backupName, const std::string &_safeBackupName);
user(AccountUid _id, const std::string &_backupName, const std::string &_safeBackupName, SDL_Texture *img);
//Attempts to read user data using _id
bool init(const u128& _id);
// Sets ID
void setUID(AccountUid _id);
//Allows user to init without reading data. For fun.
bool initNoChk(const u128& _id);
// Assigns icon
void assignIcon(SDL_Texture *_icn)
{
userIcon = _icn;
}
//Returns user ID
u128 getUID() { return userID; }
// Returns user ID
AccountUid getUID() const
{
return userID;
}
u128 getUID128() const
{
return uID128;
}
//Returns username
std::string getUsername() { return username; }
std::string getUsernameSafe() { return userSafe; }
// Returns username
std::string getUsername() const
{
return username;
}
std::string getUsernameSafe() const
{
return userSafe;
}
//Vector for storing save data info for user
std::vector<titledata> titles;
SDL_Texture *getUserIcon()
{
return userIcon;
}
void delIcon()
{
SDL_DestroyTexture(userIcon);
}
std::vector<data::userTitleInfo> titleInfo;
void addUserTitleInfo(const uint64_t &_tid,
const FsSaveDataInfo *_saveInfo,
const PdmPlayStatistics *_stats);
tex *userIcon;
private:
AccountUid userID;
u128 uID128;
u128 userID;
std::string username, userSafe;
// User icon
SDL_Texture *userIcon;
};
// User vector
//User vector
extern std::vector<user> users;
// Title data/info map
extern std::unordered_map<uint64_t, data::titleInfo> titles;
// Sets/Retrieves current user/title
void setUserIndex(unsigned _sUser);
data::user *getCurrentUser();
unsigned getCurrentUserIndex();
//Stores current data we're using so I don't have to type so much.
extern titledata curData;
extern user curUser;
}
void setTitleIndex(unsigned _sTitle);
data::userTitleInfo *getCurrentUserTitleInfo();
unsigned getCurrentUserTitleInfoIndex();
// Gets pointer to info that also has title + nacp
data::titleInfo *getTitleInfoByTID(const uint64_t &tid);
// More shortcut functions
std::string getTitleNameByTID(const uint64_t &tid);
std::string getTitleSafeNameByTID(const uint64_t &tid);
SDL_Texture *getTitleIconByTID(const uint64_t &tid);
int getTitleIndexInUser(const data::user &u, const uint64_t &tid);
extern SetLanguage sysLang;
} // namespace data
#endif // DATA_H

61
inc/file.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef FILE_H
#define FILE_H
#include <string>
#include <vector>
#include <switch.h>
#include <dirent.h>
#include "data.h"
namespace fs
{
void init();
//Mounts usr's save data for open. Returns false it fails
bool mountSave(data::user& usr, data::titledata& open);
void copyFile(const std::string& from, const std::string& to);
void copyFileCommit(const std::string& from, const std::string& to, const std::string& dev);
//Recursively copies 'from' to 'to'
void copyDirToDir(const std::string& from, const std::string& to);
//Same as above, but commits data to 'dev' after every file is closed
void copyDirToDirCommit(const std::string& from, const std::string& to, const std::string& dev);
//Recursively deletes 'path'
void delDir(const std::string& path);
//Dumps all titles for 'user'
void dumpAllUserSaves(data::user& u);
//returns file properties as C++ string
std::string getFileProps(const std::string& _path);
bool fileExists(const std::string& _path);
//Retrieves working dir string
std::string getWorkDir();
//Just retrieves a listing for _path and stores it in item vector
class dirList
{
public:
dirList(const std::string& _path);
void reassign(const std::string& _path);
void rescan();
std::string getItem(int index);
bool isDir(int index);
unsigned getCount();
private:
DIR *d;
struct dirent *ent;
std::string path;
std::vector<std::string> item;
};
}
#endif // FILE_H

View File

@ -1,65 +0,0 @@
#pragma once
#include <minizip/unzip.h>
#include <minizip/zip.h>
#include "fs/dir.h"
#include "fs/file.h"
#include "fs/fsfile.h"
#include "fs/fstype.h"
#include "fs/remote.h"
#include "fs/zip.h"
#include "ui/miscui.h"
#define BUFF_SIZE 0x4000
#define ZIP_BUFF_SIZE 0x20000
#define TRANSFER_BUFFER_LIMIT 0xC00000
namespace fs
{
copyArgs *copyArgsCreate(const std::string &src,
const std::string &dst,
const std::string &dev,
zipFile z,
unzFile unz,
bool _cleanup,
bool _trimZipPath,
uint8_t _trimPlaces);
void copyArgsDestroy(copyArgs *c);
void init();
bool mountSave(const FsSaveDataInfo &_m);
inline bool unmountSave()
{
return fsdevUnmountDevice("sv") == 0;
}
bool commitToDevice(const std::string &dev);
std::string getWorkDir();
void setWorkDir(const std::string &_w);
//Loads paths to filter from backup/deletion
void loadPathFilters(uint64_t tid);
bool pathIsFiltered(const std::string &_path);
void freePathFilters();
void createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t);
void createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid);
bool extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t);
void extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize);
uint64_t getJournalSize(const data::userTitleInfo *tinfo);
uint64_t getJournalSizeMax(const data::userTitleInfo *tinfo);
//Always threaded
void wipeSave();
void createNewBackup(void *a);
void overwriteBackup(void *a);
void restoreBackup(void *a);
void deleteBackup(void *a);
void dumpAllUserSaves(void *a);
void dumpAllUsersAllSaves(void *a);
void logOpen();
void logWrite(const char *fmt, ...);
} // namespace fs

View File

@ -1,83 +0,0 @@
#pragma once
#include "type.h"
#include <string>
#include <vector>
namespace fs
{
void mkDir(const std::string &_p);
void mkDirRec(const std::string &_p);
void delDir(const std::string &_p);
bool dirNotEmpty(const std::string &_dir);
bool isDir(const std::string &_path);
//threadInfo is optional. Only for updating task status.
void copyDirToDir(const std::string &src, const std::string &dst, threadInfo *t);
void copyDirToDirThreaded(const std::string &src, const std::string &dst);
void copyDirToDirCommit(const std::string &src, const std::string &dst, const std::string &dev, threadInfo *t);
void copyDirToDirCommitThreaded(const std::string &src, const std::string &dst, const std::string &dev);
void getDirProps(const std::string &path, unsigned &dirCount, unsigned &fileCount, uint64_t &totalSize);
class dirItem
{
public:
dirItem(const std::string &pathTo, const std::string &sItem);
std::string getItm() const
{
return itm;
}
std::string getName() const;
std::string getExt() const;
bool isDir() const
{
return dir;
}
private:
std::string itm;
bool dir = false;
};
//Just retrieves a listing for _path and stores it in item vector
class dirList
{
public:
dirList() = default;
dirList(const std::string &_path, bool ignoreDotFiles = false);
void reassign(const std::string &_path);
void rescan();
std::string getItem(int index) const
{
return item[index].getItm();
}
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;
std::vector<dirItem> item;
};
} // namespace fs

View File

@ -1,65 +0,0 @@
#pragma once
#include <string>
#include <cstdio>
#include <vector>
#include <switch.h>
#include <dirent.h>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#include "fs.h"
#include "data.h"
#include "ui.h"
namespace fs
{
//Copy args are optional and only used if passed and threaded
void copyFile(const std::string& src, const std::string& dst, threadInfo *t);
void copyFileThreaded(const std::string& src, const std::string& dst);
void copyFileCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t);
void copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev);
void fileDrawFunc(void *a);
//deletes file
void delfile(const std::string& _p);
//Dumps all titles for current user
void dumpAllUserSaves();
void getShowFileProps(const std::string& _path);
void getShowDirProps(const std::string& _path);
bool fileExists(const std::string& _path);
//Returns file size
size_t fsize(const std::string& _f);
class dataFile
{
public:
dataFile(const std::string& _path);
~dataFile();
void close(){ fclose(f); }
bool isOpen() const { return opened; }
bool readNextLine(bool proc);
//Finds where variable name ends. When a '(' or '=' is hit. Strips spaces
void procLine();
std::string getLine() const { return line; }
std::string getName() const { return name; }
//Reads until ';', ',', or '\n' is hit and returns as string.
std::string getNextValueStr();
int getNextValueInt();
private:
FILE *f;
std::string line, name;
size_t lPos = 0;
bool opened = false;
};
void logOpen();
void logWrite(const char *fmt, ...);
void logClose();
}

View File

@ -1,100 +0,0 @@
#pragma once
#include <switch.h>
#include <stdint.h>
//Bare minimum wrapper around switch fs for JKSV
#define FS_SEEK_SET 0
#define FS_SEEK_CUR 1
#define FS_SEEK_END 2
#ifdef __cplusplus
extern "C"
{
#endif
typedef struct
{
FsFile _f;
Result error;
s64 offset, fsize;
} FSFILE;
int fsremove(const char *_p);
Result fsDelDirRec(const char *_p);
char *getDeviceFromPath(char *dev, size_t _max, const char *path);
char *getFilePath(char *pathOut, size_t _max, const char *path);
bool fsMkDir(const char *_p);
/*Opens file. Device is fetched from path. Libnx romfs doesn't work with this.
Mode needs to be:
FsOpenMode_Read
FsOpenMode_Write
FsOpenMode_Append
*/
bool fsfcreate(const char *_p, int64_t crSize);
FSFILE *fsfopen(const char *_p, uint32_t mode);
/*Same as above, but FsFileSystem _s is used. Path cannot have device in it*/
FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode);
//Closes _f
inline void fsfclose(FSFILE *_f)
{
if(_f != NULL)
{
fsFileClose(&_f->_f);
free(_f);
}
}
//Seeks like stdio
inline void fsfseek(FSFILE *_f, int offset, int origin)
{
switch(origin)
{
case FS_SEEK_SET:
_f->offset = offset;
break;
case FS_SEEK_CUR:
_f->offset += offset;
break;
case FS_SEEK_END:
_f->offset = offset + _f->fsize;
break;
}
}
//Returns offset
inline size_t fsftell(FSFILE *_f) { return _f->offset; }
//Writes buf to file. Automatically resizes _f to fit buf
size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f);
//Reads to buff
inline size_t fsfread(void *buf, size_t sz, size_t count, FSFILE *_f)
{
uint64_t read = 0;
_f->error = fsFileRead(&_f->_f, _f->offset, buf, sz * count, 0, &read);
_f->offset += read;
return read;
}
//Gets byte from file
inline char fsfgetc(FSFILE *_f)
{
char ret = 0;
uint64_t read = 0;
_f->error = fsFileRead(&_f->_f, _f->offset++, &ret, 1, 0, &read);
return ret;
}
//Writes byte to file
inline void fsfputc(int ch, FSFILE *_f) { fsfwrite(&ch, 1, 1, _f); }
#ifdef __cplusplus
}
#endif

View File

@ -1,46 +0,0 @@
#pragma once
#include "data.h"
#include "miscui.h"
#include "type.h"
namespace fs
{
typedef struct
{
std::string src, dst, dev;
zipFile z;
unzFile unz;
bool cleanup = false, trimZipPath = false;
uint8_t trimZipPlaces = 0;
uint64_t offset = 0;
ui::progBar *prog;
threadStatus *thrdStatus;
Mutex arglck = 0;
void argLock() { mutexLock(&arglck); }
void argUnlock() { mutexUnlock(&arglck); }
} copyArgs;
typedef struct
{
FsSaveDataType type;
uint64_t tid;
AccountUid account;
uint16_t index;
} svCreateArgs;
typedef struct
{
const data::userTitleInfo *tinfo;
uint64_t extSize;
} svExtendArgs;
typedef struct
{
std::string path;
bool origin = false;
unsigned dirCount = 0;
unsigned fileCount = 0;
uint64_t totalSize = 0;
} dirCountArgs;
}

View File

@ -1,21 +0,0 @@
#pragma once
#include "../rfs.h"
#define JKSV_DRIVE_FOLDER "JKSV"
namespace fs
{
extern rfs::IRemoteFS *rfs;
extern std::string rfsRootID;
void remoteInit();
void remoteExit();
// Google Drive
void driveInit();
std::string driveSignInGetAuthCode();
// Webdav
void webDavInit();
}

View File

@ -1,18 +0,0 @@
#pragma once
#include <string>
#include <minizip/zip.h>
#include <minizip/unzip.h>
#include "type.h"
namespace fs
{
//threadInfo is optional and only used when threaded versions are used
void copyDirToZip(const std::string& src, zipFile dst, bool trimPath, int trimPlaces, threadInfo *t);
void copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces);
void copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t);
void copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev);
uint64_t getZipTotalSize(unzFile unz);
bool zipNotEmpty(unzFile unz);
}

View File

@ -1,66 +0,0 @@
#pragma once
#include <curl/curl.h>
#include <json-c/json.h>
#include <string>
#include <vector>
#include <unordered_map>
#include "curlfuncs.h"
#include "rfs.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
{
class gd : public rfs::IRemoteFS
{
public:
void setClientID(const std::string& _clientID) { clientID = _clientID; }
void setClientSecret(const std::string& _clientSecret) { secretID = _clientSecret; }
void setRefreshToken(const std::string& _refreshToken) { rToken = _refreshToken; }
bool exhangeAuthCode(const std::string& _authCode);
bool hasToken() { return token.empty() == false; }
bool refreshToken();
bool tokenIsValid();
void clearDriveList() { driveList.clear(); }
// TODO: This also gets files that do not belong to JKSV
void driveListInit(const std::string& _q);
void driveListAppend(const std::string& _q);
std::vector<rfs::RfsItem> getListWithParent(const std::string& _parent);
void debugWriteList();
bool createDir(const std::string& _dirName, const std::string& _parent);
// TODO: This is problematic, because multiple files could share the same name without a parent.
bool dirExists(const std::string& _dirName);
bool dirExists(const std::string& _dirName, const std::string& _parent);
bool fileExists(const std::string& _filename, const std::string& _parent);
void uploadFile(const std::string& _filename, const std::string& _parent, 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, const std::string& _parent);
// TODO: This is problematic, because multiple files could share the same name without a parent.
std::string getDirID(const std::string& _name);
std::string getDirID(const std::string& _name, const std::string& _parent);
size_t getDriveListCount() const { return driveList.size(); }
rfs::RfsItem *getItemAt(unsigned int _ind) { return &driveList[_ind]; }
private:
std::vector<rfs::RfsItem> driveList;
std::string clientID, secretID, token, rToken;
};
}

174
inc/gfx.h
View File

@ -1,26 +1,162 @@
#pragma once
#ifndef GFX_H
#define GFX_H
#include <SDL2/SDL.h>
#include "textureMgr.h"
#include <stdint.h>
#include <stdbool.h>
#include <ft2build.h>
#include FT_FREETYPE_H
namespace gfx
#ifdef __cplusplus
extern "C"
{
extern SDL_Renderer *render;
extern gfx::textureMgr *texMgr;
#endif
void init();
void exit();
void present();
//Structs
typedef struct
{
uint8_t r, g, b, a;
} color;
void drawTextf(SDL_Texture *target, int fontSize, int x, int y, const SDL_Color *c, const char *fmt, ...);
void drawTextfWrap(SDL_Texture *target, int fontSize, int x, int y, int maxWidth, const SDL_Color* c, const char *fmt, ...);
size_t getTextWidth(const char *str, int fontSize);
typedef struct
{
FT_Library lib;
FT_Face face;
FT_Error libRet, faceRet;
//Loads to buffer for speed
uint8_t *fntData;
} font;
//Shortcuts for drawing
void texDraw(SDL_Texture *target, SDL_Texture *tex, int x, int y);
void texDrawStretch(SDL_Texture *target, SDL_Texture *tex, int x, int y, int w, int h);
void texDrawPart(SDL_Texture *target, SDL_Texture *tex, int srcX, int srcY, int srcW, int srcH, int dstX, int dstY);
void drawLine(SDL_Texture *target, const SDL_Color *c, int x1, int y1, int x2, int y2);
void drawRect(SDL_Texture *target, const SDL_Color *c, int x, int y, int w, int h);
void clearTarget(SDL_Texture *target, const SDL_Color *clear);
typedef struct
{
size_t size;
unsigned width, height;
uint32_t *data;
} tex;
//Inits needed graphics stuff
bool graphicsInit(int windowWidth, int windowHeight);
//Exits needed services
bool graphicsExit();
//Flush, swap buffers
void gfxHandleBuffs();
//Creates color from uint32_t
inline void colorCreateFromU32(color *c, uint32_t clr)
{
c->a = clr >> 24 & 0xFF;
c->b = clr >> 16 & 0xFF;
c->g = clr >> 8 & 0xFF;
c->r = clr & 0xFF;
}
//Sets color to [r], [g], [b], [a]
inline void colorSetRGBA(color *c, uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a)
{
c->r = _r;
c->g = _g;
c->b = _b;
c->a = _a;
}
//Inverts color
inline void colorInvert(color *c)
{
c->r = 0xFF - c->r;
c->g = 0xFF - c->g;
c->b = 0xFF - c->b;
}
//Returns uint32_t color
inline uint32_t colorGetColor(const color c)
{
return (c.a << 24 | c.b << 16 | c.g << 8 | c.r);
}
inline color colorCreateTemp(uint32_t clr)
{
color ret;
ret.r = clr & 0xFF;
ret.g = clr >> 8 & 0xFF;
ret.b = clr >> 16 & 0xFF;
ret.a = clr >> 24 & 0xFF;
return ret;
}
//Draws text using f
void drawText(const char *str, tex *target, const font *f, int x, int y, int sz, color c);
//Returns text width
size_t textGetWidth(const char *str, const font *f, int sz);
//Clears framebuffer to c
void clearBufferColor(const color c);
//Draws rectangle at x, y with w, h
void drawRect(tex *target, int x, int y, int w, int h, const color c);
/*
TEX BEGIN
*/
//Inits empty tex
tex *texCreate(int w, int h);
//Loads PNG from path
tex *texLoadPNGFile(const char *path);
//Loads JPEG from path
tex *texLoadJPEGFile(const char *path);
//Loads jpeg from memory
tex *texLoadJPEGMem(const uint8_t *jpegData, size_t jpegSize);
//Frees memory used by t
void texDestroy(tex *t);
//Clears tex completely with c
void texClearColor(tex *in, const color c);
//Draws t at x, y
void texDraw(const tex *t, tex *target, int x, int y);
//Draws without alpha blending, faster
void texDrawNoAlpha(const tex *t, tex *target, int x, int y);
//Draws skipping every other pixel + row
void texDrawSkip(const tex *t, tex *target, int x, int y);
//Same as above, no alpha
void texDrawSkipNoAlpha(const tex *t, tex *target, int x, int y);
//Draw t inverted at x, y
void texDrawInvert(const tex *t, tex *target, int x, int y, bool alpha);
//Scales tex * scale and writes to out. Can only multiply for now
void texScaleToTex(const tex *in, tex *out, int scale);
//Draws directly to Switch's framebuffer
void texDrawDirect(const tex *in, int x, int y);
//Loads and returns font with Switch shared font loaded
font *fontLoadSharedFont(PlSharedFontType fontType);
//Loads and returns TTF font
font *fontLoadTTF(const char *path);
//Frees font
void fontDestroy(font *f);
/*
TEX END
*/
//returns framebuffer tex pointer
tex *texGetFramebuffer();
#ifdef __cplusplus
}
#endif
#endif // GFX_H

View File

@ -1,33 +0,0 @@
#pragma once
#include <vector>
#include <SDL2/SDL.h>
/*Texture manager class
Keeps pointers to ALL textures so it is not possible to forget to free them. Also keeps code a little easier to read. A little.*/
typedef enum
{
IMG_FMT_PNG,
IMG_FMT_JPG,
IMG_FMT_BMP
} imgTypes;
namespace gfx
{
class textureMgr
{
public:
textureMgr() = default;
~textureMgr();
void textureAdd(SDL_Texture *_tex);
SDL_Texture *textureCreate(int _w, int _h);
SDL_Texture *textureLoadFromFile(const char *_path);
SDL_Texture *textureLoadFromMem(imgTypes _type, const void *_dat, size_t _datSize);
void textureResize(SDL_Texture **_tex, int _w, int _h);
private:
std::vector<SDL_Texture *> textures;
};
}

61
inc/kb.h Normal file
View File

@ -0,0 +1,61 @@
#ifndef KB_H
#define KB_H
#include <string>
#include <vector>
#include "miscui.h"
namespace ui
{
//The way it should have been. Inheritance drives me insane sometimes, but they're basically the same thing.
class key : button
{
public:
key(const std::string& _txt, const char& _l, unsigned _x, unsigned _y, unsigned _w, unsigned _h);
//Returns char assigned to key
char getLet() { return let; }
//Updates displayed text
void updateText(const std::string& txt);
//toUpper
void toCaps();
//toLower
void toLower();
void draw() { button::draw();}
void update(const touchPosition& p) { button::update(p);}
int getEvent() { return button::getEvent(); }
int getX() { return button::getX(); }
int getY() { return button::getY(); }
int getW() { return w; }
int getH() { return h; }
private:
char let;
};
class keyboard
{
public:
//Builds keyboard
keyboard();
~keyboard();
void draw();
//returns string
std::string getString(const std::string& def);
private:
std::vector<key> keys;
std::string str;
int selKey = 0;
uint8_t clrSh = 0;
bool clrAdd = true;
};
}
#endif // KB_H

58
inc/menu.h Normal file
View File

@ -0,0 +1,58 @@
#ifndef MENU_H
#define MENU_H
#include <string>
#include <vector>
#include "gfx.h"
#include "miscui.h"
enum menuTouch
{
MENU_NOTHING,
MENU_DOUBLE_REL
};
namespace ui
{
class menu
{
public:
void setParams(const unsigned& _x, const unsigned& _y, const unsigned& _rW);
//Adds option
void addOpt(const std::string& add);
//Clears menu stuff
~menu();
//Handles controller input
void handleInput(const uint64_t& down, const uint64_t& held, const touchPosition& p);
//Returns selected option
int getSelected() { return selected; }
//Returns touch event from buttons
int getTouchEvent() { return retEvent; }
//Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected
void draw(const color& textClr);
//Clears and resets menu
void reset();
private:
//drawing x and y + rectangle width
unsigned x = 0, y = 0, rW = 0, rY = 0;
//Options vector
std::vector<std::string> opt;
//Selected + frame counting for auto-scroll
int selected = 0, fc = 0, start = 0, retEvent = MENU_NOTHING;
//How much we shift the color of the rectangle
uint8_t clrSh = 0;
bool clrAdd = true;
ui::touchTrack track;
std::vector<ui::button> optButtons;
};
}
#endif

87
inc/miscui.h Normal file
View File

@ -0,0 +1,87 @@
#ifndef MISCUI_H
#define MISCUI_H
enum buttonEvents
{
BUTTON_NOTHING,
BUTTON_PRESSED,
BUTTON_RELEASED
};
enum trackEvents
{
TRACK_NOTHING,
TRACK_SWIPE_UP,
TRACK_SWIPE_DOWN,
TRACK_SWIPE_LEFT,
TRACK_SWIPE_RIGHT
};
//For smaller classes that aren't easy to get lost in and general functions
namespace ui
{
//Progress bar for showing loading. Mostly so people know it didn't freeze
class progBar
{
public:
//Constructor. _max is the maximum value
progBar(const unsigned& _max);
//Updates progress
void update(const unsigned& _prog);
//Draws with text at top
void draw(const std::string& text);
private:
float max, prog, width;
};
class button
{
public:
button(const std::string& _txt, unsigned _x, unsigned _y, unsigned _w, unsigned _h);
void update(const touchPosition& p);
bool isOver();
bool wasOver();
int getEvent() { return retEvent; }
void draw();
unsigned getX() { return x; }
unsigned getY() { return y; }
unsigned getTx() { return tx; }
unsigned getTy() { return ty; }
protected:
bool pressed = false, first = false;
int retEvent = BUTTON_NOTHING;
unsigned x, y, w, h;
unsigned tx, ty;
std::string text;
touchPosition prev, cur;
};
class touchTrack
{
public:
void update(const touchPosition& p);
int getEvent() { return retTrack; }
private:
touchPosition pos[5];
int retTrack = TRACK_NOTHING;
int curPos = 0, avX = 0, avY = 0;
};
//General use
void showMessage(const std::string& mess);
void showError(const std::string& mess, const Result& r);
bool confirm(const std::string& q);
bool confirmTransfer(const std::string& f, const std::string& t);
bool confirmDelete(const std::string& p);
void drawTextbox(unsigned x, unsigned y, unsigned w, unsigned h);
}
#endif // MISCUI_H

View File

@ -1,53 +0,0 @@
#pragma once
#include <string>
#include "curlfuncs.h"
#include <mutex>
#define UPLOAD_BUFFER_SIZE 0x8000
#define DOWNLOAD_BUFFER_SIZE 0xC00000
#define USER_AGENT "JKSV"
namespace rfs {
typedef struct
{
std::string name, id, parent;
bool isDir = false;
unsigned int size;
} RfsItem;
class IRemoteFS
{
public:
virtual ~IRemoteFS() {} // Virtual destructor to allow correct deletion through the base class pointer
virtual bool createDir(const std::string& _dirName, const std::string& _parent) = 0;
virtual bool dirExists(const std::string& _dirName, const std::string& _parent) = 0;
virtual bool fileExists(const std::string& _filename, const std::string& _parent) = 0;
virtual void uploadFile(const std::string& _filename, const std::string& _parent, curlFuncs::curlUpArgs *_upload) = 0;
virtual void updateFile(const std::string& _fileID, curlFuncs::curlUpArgs *_upload) = 0;
virtual void downloadFile(const std::string& _fileID, curlFuncs::curlDlArgs *_download) = 0;
virtual void deleteFile(const std::string& _fileID) = 0;
virtual std::string getFileID(const std::string& _name, const std::string& _parent) = 0;
virtual std::string getDirID(const std::string& _name, const std::string& _parent) = 0;
virtual std::vector<RfsItem> getListWithParent(const std::string& _parent) = 0;
};
// Shared multi-threading definitions
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;
extern std::vector<uint8_t> downloadBuffer;
void writeThread_t(void *a);
size_t writeDataBufferThreaded(uint8_t *buff, size_t sz, size_t cnt, void *u);
}

View File

@ -1,28 +0,0 @@
#pragma once
#include <string>
#include <switch.h>
//Misc stuff for new menu code
typedef void (*funcPtr)(void *);
class threadStatus
{
public:
void setStatus(const char *fmt, ...);
void getStatus(std::string& statusOut);
private:
Mutex statusLock = 0;
std::string status;
};
typedef struct
{
bool running = false, finished = false;
Thread thrd;
ThreadFunc thrdFunc;
void *argPtr = NULL;
funcPtr drawFunc = NULL;//Draw func is passed threadInfo pointer too
threadStatus *status;
} threadInfo;

104
inc/ui.h
View File

@ -1,6 +1,6 @@
#pragma once
#ifndef UI_H
#define UI_H
#include <switch.h>
#include <vector>
#include <string>
@ -8,103 +8,61 @@
#include "gfx.h"
//ui headers - split up to keep a bit more organized
#include "ui/miscui.h"
#include "ui/uistr.h"
#include "ui/ttlview.h"
#include "ui/thrdProc.h"
#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"
#include "kb.h"
#include "menu.h"
#include "miscui.h"
#include "clsui.h"
#include "uiupdate.h"
enum menuState
{
USR_SEL,
TTL_SEL,
FLD_SEL,
ADV_MDE,
EX_MNU,
OPT_MNU,
FIL_MDE
CLS_USR,
CLS_TTL
};
namespace ui
{
//Classic mode/text menus
extern bool clsMode;
//Current menu/ui state
extern int mstate, prevState;
//Slide/animation scaling
extern float animScale;
//Loading glyph
extern const std::string loadGlyphArray[];
//pad data cause i don't know where else to put it
extern PadState pad;
extern HidTouchScreenState touchState;
static inline void updateInput() { touchState = {0}; padUpdate(&pad); hidGetTouchScreenStates(&touchState, 1); }
inline uint64_t padKeysDown() { return padGetButtonsDown(&pad); }
inline uint64_t padKeysHeld() { return padGetButtons(&pad); }
inline uint64_t padKeysUp() { return padGetButtonsUp(&pad); }
inline void changeState(int newState)
{
prevState = mstate;
mstate = newState;
}
//Holds theme set id
extern ColorSetId thmID;
extern int mstate;
//Both UI modes need access to this
extern std::string folderMenuInfo;
/*Colors
clearClr = color to clear buffer
txtCont = text that contrasts clearClr
txtDiag = text color for dialogs
*/
extern SDL_Color clearClr, transparent, txtCont, txtDiag, rectLt, rectSh, tboxClr, sideRect, divClr, heartColor, slidePanelColor;
//Colors to use now that I added theme detection
extern color clearClr, mnuTxt, txtClr, rectLt, rectSh, tboxClr;
//Button tex
extern tex *buttonA, *buttonB, *buttonX, *buttonY, *buttonMin;
//Textbox graphics
extern SDL_Texture *cornerTopLeft, *cornerTopRight, *cornerBottomLeft, *cornerBottomRight;
//Menu bounding
extern SDL_Texture *mnuTopLeft, *mnuTopRight, *mnuBotLeft, *mnuBotRight;
extern tex *cornerTopLeft, *cornerTopRight, *cornerBottomLeft, *cornerBottomRight,\
*horEdgeTop, *horEdgeBot, *vertEdgeLeft, *vertEdgeRight;
//Covers left and right of progress bar to fake being not a rectangle.
extern SDL_Texture *progCovLeft, *progCovRight, *diaBox;
//Shared font
extern font *shared;
//Side bar from Freebird. RIP.
extern SDL_Texture *sideBar;
extern std::vector<ui::button> selButtons;
//Sets colors and loads font for icon creation
void initTheme();
//Loads graphics and stuff
//Loads in the A, B, X, Y button graphics
void init();
void exit();
//Inits HID
void hidInit();
//Adds a panel pointer to a vector since they need to be drawn over everything else
int registerMenu(ui::menu *m);
int registerPanel(ui::slideOutPanel *sop);
threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc);
//Just draws a screen and flips JIC boot takes long.
void showLoadScreen();
//Prepares ui
//Sets up buttons for icon touchin
void setupSelButtons();
//Clears and draws general stuff used by multiple screens
void drawUI();
//switch case so we don't have problems with multiple main loops like 3DS
bool runApp();
void showPopMessage(int frameCount, const char *fmt, ...);
//Used for multiple menu functions/callback
void toTTL(void *);
void runApp(const uint64_t& down, const uint64_t& held, const touchPosition& p);
}
#endif

View File

@ -1,10 +0,0 @@
#pragma once
namespace ui
{
extern ui::menu *extMenu;
void extInit();
void extExit();
void extUpdate();
void extDraw(SDL_Texture *target);
}

View File

@ -1,19 +0,0 @@
#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();
}

View File

@ -1,10 +0,0 @@
#pragma once
namespace ui
{
void fmInit();
void fmExit();
void fmPrep(FsSaveDataType _type, const std::string &_dev, const std::string &_baseSDMC, bool _commit);
void fmUpdate();
void fmDraw(SDL_Texture *target);
} // namespace ui

View File

@ -1,196 +0,0 @@
#pragma once
#include <SDL2/SDL.h>
#include <vector>
#include "gfx.h"
#include "type.h"
#define POP_FRAME_DEFAULT 130
#define MENU_FONT_SIZE_DEFAULT 18
#define MENU_MAX_SCROLL_DEFAULT 15
typedef enum
{
MENU_X,
MENU_Y,
MENU_RECT_WIDTH,
MENU_RECT_HEIGHT,
MENU_FONT_SIZE,
MENU_MAX_SCROLL
} menuParams;
//For smaller classes that aren't easy to get lost in and general functions
namespace ui
{
typedef struct
{
std::string text;
bool hold;
funcPtr confFunc, cancelFunc;
void *args;
unsigned lgFrame = 0, frameCount = 0; //To count frames cause I don't have time and am lazy
} confirmArgs;
typedef struct
{
funcPtr func = NULL;
void *args = NULL;
HidNpadButton button = (HidNpadButton)0;
} menuOptEvent;
typedef struct
{
SDL_Texture *icn = NULL;
std::string txt;
int txtWidth;
std::vector<menuOptEvent> events;
} menuOpt;
class menu
{
public:
menu() = default;
menu(int _x, int _y, int _rW, int _fS, int _mL);
void editParam(int _param, int newVal);
//Gets executed when menu changes at all
void setOnChangeFunc(funcPtr func)
{
onChange = func;
}
//executed when .update() is called.
void setCallback(funcPtr _callback, void *args)
{
callback = _callback;
callbackArgs = args;
}
//Adds option.
int addOpt(SDL_Texture *_icn, const std::string &add);
//Adds an function to be executed on pressing button specified
void optAddButtonEvent(unsigned _ind, HidNpadButton _button, funcPtr _func, void *args);
//Changes opt text
void editOpt(int ind, SDL_Texture *_icn, const std::string &ch);
size_t getOptCount()
{
return opt.size();
}
int getOptPos(const std::string &txt);
//Clears menu stuff
~menu();
//Handles controller input and executes functions for buttons if they're set
void update();
//Returns selected option
int getSelected()
{
return selected;
}
//Returns menu option count
int getCount()
{
return opt.size();
}
//Draws the menu at x and y. rectWidth is the width of the rectangle drawn under the selected
void draw(SDL_Texture *target, const SDL_Color *textClr, bool drawText);
//Clears and resets menu
void reset();
//Resets selected + start
void resetSel()
{
selected = 0;
}
//Enables control/disables drawing select box
void setActive(bool _set);
bool getActive()
{
return isActive;
}
private:
//drawing x and y + rectangle width/height. Height is calc'd with font size
int x = 0, mY = 0, tY = 0, y = 0, rW = 0, rY = 0, fSize = 0, rH = 0, mL = 0;
//Options vector
std::vector<ui::menuOpt> opt;
//Selected + frame counting for auto-scroll. Hover count is to not break autoscroll
int selected = 0, fc = 0, hoverCount = 0, spcWidth = 0;
//How much we shift the color of the rectangle
uint8_t clrSh = 0;
bool clrAdd = true, isActive = true, hover = false;
//Option buffer. Basically, text is draw to this so it can't overlap. Also allows scrolling
SDL_Texture *optTex;
funcPtr onChange = NULL, callback = NULL;
void *callbackArgs, *funcArgs;
};
//Progress bar for showing loading. Mostly so people know it didn't freeze
class progBar
{
public:
//Constructor. _max is the maximum value
progBar() = default;
progBar(uint64_t _max) : max(_max) {};
void setMax(uint64_t _max)
{
max = _max;
}
//Updates progress
void update(uint64_t _prog);
//Draws with text at top
void draw(const std::string &text);
private:
uint64_t max = 0, prog = 0;
float width = 0;
};
typedef struct
{
std::string message;
int rectWidth = 0, frames = 0, y = 720;
} popMessage;
class popMessageMngr
{
public:
~popMessageMngr();
void update();
void popMessageAdd(const std::string &mess, int frameTime);
void draw();
private:
std::vector<popMessage>
popQueue; //All graphics need to be on main thread. Directly adding will cause text issues
std::vector<popMessage> message;
};
//General use
ui::confirmArgs *confirmArgsCreate(bool _hold,
funcPtr _confFunc,
funcPtr _cancelFunc,
void *_funcArgs,
const char *fmt,
...);
void confirm(void *a);
void showMessage(const char *fmt, ...);
bool confirmTransfer(const std::string &f, const std::string &t);
bool confirmDelete(const std::string &p);
void drawBoundBox(SDL_Texture *target, int x, int y, int w, int h, uint8_t clrSh);
void drawTextbox(SDL_Texture *target, int x, int y, int w, int h);
} // namespace ui

View File

@ -1,13 +0,0 @@
#pragma once
#include <SDL2/SDL.h>
namespace ui
{
void settInit();
void settExit();
void settUpdate();
void settDraw(SDL_Texture *target);
extern ui::menu *settMenu;
}

View File

@ -1,35 +0,0 @@
#pragma once
namespace ui
{
//Maybe more later *if* needed, but not now.
typedef enum
{
SLD_LEFT,
SLD_RIGHT
} slidePanelOrientation;
//_draw is called and passed the panel texture/target when this.draw() is called.
class slideOutPanel
{
public:
slideOutPanel(int _w, int _h, int _y, slidePanelOrientation _side, funcPtr _draw);
void resizePanel(int _w, int _h, int _y);
void update();
void setCallback(funcPtr _cb, void *_args) { callback = _cb; cbArgs = _args; }
void openPanel() { open = true; }
void closePanel() { open = false; }
void setX(int _nX){ x = _nX; };
bool isOpen() { return open; }
void draw(const SDL_Color *backCol);
private:
int w, h, x, y;
uint8_t sldSide;
bool open = false;
SDL_Texture *panel;
funcPtr drawFunc, callback = NULL;
void *cbArgs = NULL;
};
}

View File

@ -1,24 +0,0 @@
#pragma once
#include "type.h"
namespace ui
{
class threadProcMngr
{
public:
~threadProcMngr();
//Draw function is used and called to draw on overlay
threadInfo *newThread(ThreadFunc func, void *args, funcPtr _drawFunc);
void update();
void draw();
bool empty() { return threads.empty(); }
private:
std::vector<threadInfo *> threads;
uint8_t lgFrame = 0, clrShft = 0;
bool clrAdd = true;
unsigned frameCount = 0;
Mutex threadLock = 0;
};
}

View File

@ -1,17 +0,0 @@
#pragma once
namespace ui
{
void ttlInit();
void ttlExit();
void ttlSetActive(int usr, bool _set, bool _showSel);
void ttlRefresh();
//JIC for func ptr
void ttlReset();
void ttlUpdate();
void ttlDraw(SDL_Texture *target);
//File mode needs access to this.
extern ui::slideOutPanel *ttlOptsPanel;
}

View File

@ -1,56 +0,0 @@
#pragma once
#include <SDL2/SDL.h>
#include "type.h"
#include "data.h"
namespace ui
{
class titleTile
{
public:
titleTile(unsigned _w, unsigned _h, bool _fav, SDL_Texture *_icon)
{
w = _w;
h = _h;
wS = _w;
hS = _h;
fav = _fav;
icon = _icon;
}
void draw(SDL_Texture *target, int x, int y, bool sel);
private:
unsigned w, h, wS, hS;
bool fav = false;
SDL_Texture *icon;
};
//Todo less hardcode etc
class titleview
{
public:
titleview(const data::user& _u, int _iconW, int _iconH, int _horGap, int _vertGap, int _rowCount, funcPtr _callback);
~titleview();
void update();
void refresh();
void setActive(bool _set, bool _showSel) { active = _set; showSel = _showSel; }
bool getActive() { return active; }
void setSelected(int _set) { selected = _set; }
int getSelected() { return selected; }
void draw(SDL_Texture *target);
private:
const data::user *u;//Might not be safe. Users *shouldn't* be touched after initial load
bool active = false, showSel = false, clrAdd = true;
uint8_t clrShft = 0;
funcPtr callback = NULL;
int x = 200, y = 62, selected = 0, selRectX = 10, selRectY = 45;
int iconW, iconH, horGap, vertGap, rowCount;
std::vector<ui::titleTile *> tiles;
};
}

View File

@ -1,15 +0,0 @@
#pragma once
#include <map>
//Strings since translation support
namespace ui
{
void initStrings();
void loadTrans();
void saveTranslationFiles(void *a);
extern std::map<std::pair<std::string, int>, std::string> strings;
inline std::string getUIString(const std::string& _name, int ind){ return strings[std::make_pair(_name, ind)]; }
inline const char *getUICString(const std::string& _name, int ind){ return strings[std::make_pair(_name, ind)].c_str(); }
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace ui
{
void usrInit();
void usrExit();
void usrRefresh();
void usrUpdate();
void usrDraw(SDL_Texture *target);
//A lot of stuff needs access to these
extern ui::menu *usrMenu;
extern ui::slideOutPanel *usrSelPanel;
}

19
inc/uiupdate.h Normal file
View File

@ -0,0 +1,19 @@
#ifndef UIUPDATE_H
#define UIUPDATE_H
//Contains declarations of ui updating functions
namespace ui
{
void updateUserMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void updateTitleMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void updateFolderMenu(const uint64_t& down, const uint64_t& held, const touchPosition& p);
void updateAdvMode(const uint64_t& down, const uint64_t& held, const touchPosition& p);
//needed here since it uses static menu
void folderMenuPrepare(data::user& usr, data::titledata& dat);
void advCopyMenuPrep();
void advModePrep();
}
#endif // USRSEL_H

View File

@ -1,161 +1,32 @@
#pragma once
#ifndef UTIL_H
#define UTIL_H
#include "data.h"
#include "file.h"
#include "gfx.h"
#include "ui.h"
#include "file.h"
namespace util
{
enum
{
DATE_FMT_YMD,
DATE_FMT_YDM,
DATE_FMT_HOYSTE,
DATE_FMT_JHK,
DATE_FMT_ASC
};
//Returns string with date + time
std::string getDateTime();
typedef enum
{
CPU_SPEED_204MHz = 204000000,
CPU_SPEED_306MHz = 306000000,
CPU_SPEED_408MHz = 408000000,
CPU_SPEED_510MHz = 510000000,
CPU_SPEED_612MHz = 612000000,
CPU_SPEED_714MHz = 714000000,
CPU_SPEED_816MHz = 816000000,
CPU_SPEED_918MHz = 918000000,
CPU_SPEED_1020MHz = 1020000000, //Default
CPU_SPEED_1122MHz = 1122000000,
CPU_SPEED_1224MHz = 1224000000,
CPU_SPEED_1326MHz = 1326000000,
CPU_SPEED_1428MHz = 1428000000,
CPU_SPEED_1581MHz = 1581000000,
CPU_SPEED_1683MHz = 1683000000,
CPU_SPEED_1785MHz = 1785000000
} cpuSpds;
//Creates Dir 'JKSV/[title]
void makeTitleDir(data::user& u, data::titledata& t);
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;
//Returns 'JKSV/[title]/'
std::string getTitleDir(data::user& u, data::titledata& t);
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);
//Just returns string with '\n' inserted.
std::string getWrappedString(const std::string& s, const unsigned& sz, const unsigned& maxWidth);
//Copys dir list to a menu with 'D: ' + 'F: '
void copyDirListToMenu(const fs::dirList &d, ui::menu &m);
void copyDirListToMenu(fs::dirList& d, ui::menu& m);
//Removes last folder from '_path'
void removeLastFolderFromString(std::string &_path);
size_t getTotalPlacesInPath(const std::string &_path);
void trimPath(std::string &_path, uint8_t _places);
void removeLastFolderFromString(std::string& _path);
inline bool isASCII(uint32_t t)
{
return t > 30 && t < 127;
}
std::string safeString(const std::string& s);
std::string safeString(const std::string &s);
std::string getStringInput(SwkbdType _type,
const std::string &def,
const std::string &head,
size_t maxLength,
unsigned dictCnt,
const std::string dictWords[]);
std::string getExtensionFromString(const std::string &get);
std::string getFilenameFromPath(const std::string &get);
std::string generateAbbrev(uint64_t tid);
//removes char from C++ string
void stripChar(char _c, std::string &_s);
void replaceStr(std::string &_str, const std::string &_find, const std::string &_rep);
//For future external translation support. Replaces [button] with button chars
void replaceButtonsInString(std::string &rep);
//Creates a basic generic icon for stuff without one
SDL_Texture *createIconGeneric(const char *txt, int fontSize, bool clearBack);
inline u128 accountUIDToU128(AccountUid uid)
{
return ((u128)uid.uid[0] << 64 | uid.uid[1]);
}
inline AccountUid u128ToAccountUID(u128 id)
{
AccountUid ret;
ret.uid[0] = id >> 64;
ret.uid[1] = id;
return ret;
}
inline std::string getIDStr(uint64_t _id)
{
char tmp[18];
sprintf(tmp, "%016lX", _id);
return std::string(tmp);
}
inline std::string getIDStrLower(uint64_t _id)
{
char tmp[18];
sprintf(tmp, "%08X", (uint32_t)_id);
return std::string(tmp);
}
inline std::string generatePathByTID(uint64_t tid)
{
return fs::getWorkDir() + data::getTitleSafeNameByTID(tid) + "/";
}
std::string getSizeString(uint64_t _size);
inline void createTitleDirectoryByTID(uint64_t tid)
{
std::string makePath = fs::getWorkDir() + data::getTitleSafeNameByTID(tid);
mkdir(makePath.c_str(), 777);
}
void sysBoost();
void sysNormal();
inline bool isApplet()
{
AppletType type = appletGetAppletType();
return type == AppletType_LibraryApplet;
}
void checkForUpdate(void *a);
} // namespace util
std::string getInfoString(data::user& u, data::titledata& d);
}
#endif // UTIL_H

View File

@ -1,53 +0,0 @@
#pragma once
#include <curl/curl.h>
#include <string>
#include <tinyxml2.h>
#include "rfs.h"
namespace rfs {
// Note: Everything declared an "id" is the full path component from the origin to the resource starting with a "/".
// Note: Directories ALWAYS have a trailing / while files NEVER have a trailing /
// e.g. /<basePath>/JKSV/
// e.g. /<basePath>/JKSV/<title-id>/
// e.g. /<basePath>/JKSV/<title-id>/<file>
// e.g. /
// other string arguments never have any leading or trailing "/"
class WebDav : public IRemoteFS {
private:
CURL* curl;
std::string origin;
std::string basePath;
std::string username;
std::string password;
std::vector<RfsItem> parseXMLResponse(const std::string& xml);
bool resourceExists(const std::string& id);
std::string appendResourceToParentId(const std::string& resourceName, const std::string& parentId, bool isDir);
std::string getNamespacePrefix(tinyxml2::XMLElement* root, const std::string& nsURI);
public:
WebDav(const std::string& origin,
const std::string& username,
const std::string& password);
~WebDav();
bool createDir(const std::string& dirName, const std::string& parentId);
bool dirExists(const std::string& dirName, const std::string& parentId);
bool fileExists(const std::string& filename, const std::string& parentId);
void uploadFile(const std::string& filename, const std::string& parentId, 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 getFileID(const std::string& name, const std::string& parentId);
std::string getDirID(const std::string& dirName, const std::string& parentId);
std::vector<RfsItem> getListWithParent(const std::string& _parent);
std::string getDisplayNameFromURL(const std::string &url);
};
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 729 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 721 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 707 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 557 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 548 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 778 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 767 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 713 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 693 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 253 B

View File

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,218 +0,0 @@
appletModeWarning = 0, "*ADVERTENCIA*: JKSV se está ejecutando en modo 'applet'. Algunas características no funcionarán."
author = 0, "Impeeza"
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 todos los Datos de Partidas Guardadas en este sistema para #%s#? ¡Puede tomar un tiempo dependiendo de la cantidad de títulos sean encontrados!"
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, "Al descargar este respaldo desde el servidor remoto se reemplazará el que actualmente está en la tarjeta SD, ¿Continuar?"
#<====================================================
confirmOverwrite = 0, "¿Sobrescribir #%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, "Número de Usuarios: "
debugStatus = 1, "Usuario Actual: "
debugStatus = 2, "Título Actual: "
debugStatus = 3, "Título Seguro: "
debugStatus = 4, "Tipo órden: "
#<====================================================
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Si [A]"
extrasMenu = 0, "Navegador de SD a SD"
extrasMenu = 1, "Navegar 'ProdInfo'"
extrasMenu = 2, "Navegar 'Safe'"
extrasMenu = 3, "Navegar 'System'"
extrasMenu = 4, "Navegar 'User'"
extrasMenu = 5, "Eliminar actualizaciones pendientes"
extrasMenu = 6, "Detener proceso"
extrasMenu = 7, "Montar 'System Save'"
extrasMenu = 8, "Recargar Lista de Títulos"
extrasMenu = 9, "Navegar 'Process RomFS'"
extrasMenu = 10, "Realizar respaldo de la carpeta de JKSV"
extrasMenu = 11, "*[DEV]* Extraer Archivos de Lenguaje actuales"
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] Selecionar [Y] Restaurar [X] Borrar [ZR] Subir [B] Cerrar"
#<====================================================
helpSettings = 0, "[A] Cambiar [X] Predeterminados [B] Atrás"
helpTitle = 0, "[A] Seleccionar [L][R] Cambiar Página [Y] Favoritos [X] Opciones de Títulos [B] Atrás"
helpUser = 0, "[A] Seleccionar [Y] Extraer Todos [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, "Tiempo Jugado: %02d:%02d"
infoStatus = 3, "Veces Ejecutado: %u"
infoStatus = 4, "Editor: %s"
infoStatus = 5, "Tipo Partida Guardada: %s"
infoStatus = 6, "Índice de Caché: %u"
infoStatus = 7, "Usuario: %s"
infoStatus = 9, ""
#<=====================================================
loadingStartPage = 0, "Cargando..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Configs."
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, "Falla al iniciar Google Drive."
popRemoteNotActive = 0, "Servidor Remoto no está disponible."
popDriveStarted = 0, "Se ha iniciado Google Drive correctamente."
popWebdavStarted = 0, "Se ha iniciado Webdav Correctamente."
popWebdavFailed = 0, "Falla al iniciar Webdav."
#<====================================================
popErrorCommittingFile = 0, "¡Error guardando archivo!"
popFolderIsEmpty = 0, "¡La carpeta está vacía!"
popProcessShutdown = 0, "#%s# Apagado satisfactorio."
#CHANGED=============================================>
popSVIExported = 0, "SVI Exportado."
#<====================================================
popSaveIsEmpty = 0, "¡Partida Guardada está vacía!"
popTrashEmptied = 0, "Papelera Vaciada"
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# expandida 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, "Device"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Caché"
saveTypeMainMenu = 3, "Sistema"
saveTypeMainMenu = 4, "BCAT de Sistema"
saveTypeMainMenu = 5, "SysTemp Storagetem"
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 idioma Inglés: "
settingsMenu = 18, "Habilitar papelera: "
settingsMenu = 19, "Ordenar Títulos: "
settingsMenu = 20, "Escala de Animación: "
settingsMenu = 21, "Subir automáticamente a GDrive/Webdav: "
settingsOff = 0, "Apagado"
settingsOn = 0, ">Encendido>"
sortType = 0, "Alfabéticamente"
sortType = 1, "Por Duración Juegos"
sortType = 2, "Recientemente 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, "Calculando tamaño de partida guardada..."
#<====================================================
threadStatusCheckingForUpdate = 0, "Verificando actualizaciones..."
#CHANGED=============================================>
threadStatusCompressingSaveForUpload = 0, "Comprimiendo #%s# para subirlo..."
#<====================================================
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, "Descargando #%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, "Guardando archivo maestro..."
#CHANGED=============================================>
threadStatusUploadingFile = 0, "Subiendo #%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, "Exportar 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

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,171 +0,0 @@
author = 0, "Shadow2560"
confirmBlacklist = 0, "Souhaitez-vous vraiment ajouter #%s# à votre liste noire?"
confirmCopy = 0, "Souhaitez-vous vraiment copier #%s# vers #%s#?"
confirmCreateAllSaveData = 0, "Souhaitez-vous vraiment créer toutes les données de sauvegarde de ce système pour #%s# ? Cela peut prendre un certain temps en fonction du nombre de titres trouvés."
confirmDelete = 0, "Souhaitez-vous vraiment supprimer #%s# ? *Ceci sera permanent* !"
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 ?"
confirmDriveOverwrite = 0, "Le téléchargement de cette sauvegarde depuis le disque dur écrasera celle qui se trouve sur votre carte SD. Continuer?"
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#?"
debugStatus = 0, "Nombre d'utilisateurs: "
debugStatus = 1, "Utilisateur actuel: "
debugStatus = 2, "Titre actuel: "
debugStatus = 3, "Titre sauvegardé: "
debugStatus = 4, "Type de tri: "
dialogNo = 0, "Non [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Oui [A]"
extrasMenu = 0, "Explorateur SD vers SD"
extrasMenu = 1, "BIS: ProdInfoF"
extrasMenu = 2, "BIS: Safe"
extrasMenu = 3, "BIS: System"
extrasMenu = 4, "BIS: User"
extrasMenu = 5, "Supprimer la mise à jour en attente"
extrasMenu = 6, "Terminer le processus"
extrasMenu = 7, "Monter la sauvegarde système"
extrasMenu = 8, "Re-scanner les titres"
extrasMenu = 9, "Monter le processus RomFS"
extrasMenu = 10, "Sauvegarder le répertoire de JKSV"
extrasMenu = 11, "*[DEV]* Forcer la langue en en-US"
fileModeFileProperties = 0, "Chemin: %s\nTaille: %s"
fileModeFolderProperties = 0, "Chemin: %s\nSous-répertoires: %u\nNombre de fichiers: %u\nTaille totale: %s"
fileModeMenu = 0, "Copier vers "
fileModeMenu = 1, "Supprimer"
fileModeMenu = 2, "Renommer"
fileModeMenu = 3, "Créer un nouveau dossier"
fileModeMenu = 4, "Propriétés"
fileModeMenu = 5, "Fermer"
fileModeMenu = 6, "Ajouter aux filtres de chemins"
fileModeMenuMkDir = 0, "Nouveau"
folderMenuNew = 0, "Nouvelle sauvegarde"
helpFolder = 0, "[A] Sélectionner [Y] Restorer [X] Suprimer [ZR] Upload [B] Fermer"
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: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Temps de jeu: %02d:%02d"
infoStatus = 3, "Nombre de fois lancé: %u"
infoStatus = 4, "Auteur: %s"
infoStatus = 5, "Type de sauvegarde: %s"
infoStatus = 6, "Index du Cache: %u"
infoStatus = 7, "Utilisateur: %s"
loadingStartPage = 0, "Chargement..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Paramètres"
onlineErrorConnecting = 0, "Erreur de connection!"
onlineNoUpdates = 0, "Aucune mise à jour disponible."
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#"
popDriveFailed = 0, "Echec du démarrage de Google Drive."
popRemoteNotActive = 0, "Remote n'est pas utilisable"
popDriveStarted = 0, "Google Drive lancé avec succès."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
popErrorCommittingFile = 0, "Erreur d'ajout du fichier à la sauvegarde!"
popFolderIsEmpty = 0, "Le dossier est vide!"
popProcessShutdown = 0, "#%s# terminé avec succès."
popSVIExported = 0, "SVI Exporté."
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."
saveDataCreatedForUser = 0, "Données de sauvegarde créée pour %s!"
saveDataCreationFailed = 0, "Echec de la création des données de sauvegarde!"
saveDataDeleteAllUser = 0, "*Souhaitez-vous vraiment supprimer toutes les données de sauvegarde pour %s?*"
saveDataDeleteSuccess = 0, "Données de la sauvegarde pour #%s# Supprimée!"
saveDataExtendFailed = 0, "Echec de l'extention des données de la sauvegarde."
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"
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"
saveTypeMainMenu = 3, "Système"
saveTypeMainMenu = 4, "BCAT système"
saveTypeMainMenu = 5, "Stockage SysTemp"
settingsMenu = 0, "Vider la corbeille"
settingsMenu = 1, "Vérifier les mises à jour"
settingsMenu = 2, "Définir le dossier de sortie de JKSV"
settingsMenu = 3, "Modifier les titres de la liste noire"
settingsMenu = 4, "Supprimer toutes les sauvegardes sauvegardées"
settingsMenu = 5, "Inclure les sauvegardes du matériel avec les utilisateurs: "
settingsMenu = 6, "Sauvegarder automatiquement avant la restauration: "
settingsMenu = 7, "Nom automatique des sauvegardes: "
settingsMenu = 8, "Overclock/CPU Boost: "
settingsMenu = 9, "Maintenir pour supprimer: "
settingsMenu = 10, "Maintenir pour restaurer: "
settingsMenu = 11, "Maintenir pour écraser: "
settingsMenu = 12, "Forcer le montage: "
settingsMenu = 13, "Compte des sauvegardes système: "
settingsMenu = 14, "Activer l'écriture pour les sauvegardes système: "
settingsMenu = 15, "Utiliser directement les commandes FS : "
settingsMenu = 16, "Exporter les sauvegardes en ZIP: "
settingsMenu = 17, "Forcer l'utilisation de l'anglais: "
settingsMenu = 18, "Activer la corbeille: "
settingsMenu = 19, "Type de tri des titres: "
settingsMenu = 20, "Échelle d'animation: "
settingsOff = 0, "Désactivé"
settingsOn = 0, ">Activé>"
sortType = 0, "Alphabétique"
sortType = 1, "Temps de jeu"
sortType = 2, "Joué dernièrement"
swkbdEnterName = 0, "Entrez un nouveau nom"
swkbdExpandSize = 0, "Entrez la nouvelle taille en MB"
swkbdMkDir = 0, "Entrez un nom de dossier"
swkbdNewSafeTitle = 0, "Entrez un nouveau nom de dossier"
swkbdProcessID = 0, "Entrez l'ID du processus"
swkbdRename = 0, "Entrez un nouveau nom pour l'objet"
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..."
threadStatusCalculatingSaveSize = 0, "Calcul de la taille de la sauvegarde..."
threadStatusCheckingForUpdate = 0, "Vérification de mises à jour..."
threadStatusCompressingSaveForUpload = 0, "Compression de #%s# pour l'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..."
threadStatusDownloadingFile = 0, "Téléchargement de #%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..."
threadStatusUploadingFile = 0, "Upload de #%s#..."
titleOptions = 0, "Information"
titleOptions = 1, "Liste noir"
titleOptions = 2, "Changer le dossier de sortie"
titleOptions = 3, "Ouvrir en mode fichier"
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"
titleOptions = 8, "Exporter SVI"
translationMainPage = 0, "Traduction: "
userOptions = 0, "Dumper tout pour"
userOptions = 1, "Sauvegarder la sauvegarde"
userOptions = 2, "Sauvegarder toutes les sauvegardes"
userOptions = 3, "Supprimer toutes les sauvegardes de l'utilisateur"

View File

@ -1,171 +0,0 @@
author = 0, "SimoCasa"
confirmBlacklist = 0, "Sei sicuro di voler aggiungere #%s# alla tua blacklist?"
confirmCopy = 0, "Sei sicuro di voler copiare #%s# in #%s#?"
confirmCreateAllSaveData = 0, "Sei sicuro di voler creare tutti i dati di salvataggio su questo sistema per #%s#? Può metterci un po' di tempo in base ai titoli trovati."
confirmDelete = 0, "Sei sicuro di voler cancellare #%s#? *È permanente*!"
confirmDeleteBackupsAll = 0, "Sei sicuro di voler cancellare *tutti* i tuoi backup dei salvataggi di gioco?"
confirmDeleteBackupsTitle = 0, "Sei sicuro di voler cancellare tutti i salvataggi di backup di #%s#?"
confirmDeleteSaveData = 0, "*ATTENZIONE*: Questo *cancellerà* il salvataggio di #%s# *dal tuo sistema*. Sei sicuro di volerlo fare?"
confirmDriveOverwrite = 0, "Scaricando questo backup da Drive sovrascriverai quello nella tua scheda SD. Vuoi continuare?"
confirmOverwrite = 0, "Sei sicuro di voler sovrascrivere #%s#?"
confirmResetSaveData = 0, "*ATTENZIONE*: Questo *resetterà* i dati di salvataggio per questo gioco come se non fosse mai stato eseguito prima. Sei sicuro di volerlo fare?"
confirmRestore = 0, "Sei sicuro di voler ripristinare #%s#?"
debugStatus = 0, "Numero Utenti: "
debugStatus = 1, "Utente Corrente: "
debugStatus = 2, "Titolo Corrente: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "Tipo Ordinamento: "
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Si [A]"
extrasMenu = 0, "Browser da SD a SD"
extrasMenu = 1, "BIS: ProdInfoF"
extrasMenu = 2, "BIS: Safe"
extrasMenu = 3, "BIS: System"
extrasMenu = 4, "BIS: User"
extrasMenu = 5, "Rimuovi Aggiornamento in attesa"
extrasMenu = 6, "Termina Processo"
extrasMenu = 7, "Monta Salvataggio di Sistema"
extrasMenu = 8, "Riscansiona Titoli"
extrasMenu = 9, "Monta Processo RomFS"
extrasMenu = 10, "Backup cartella JKSV"
extrasMenu = 11, "*[DEV]* Output en-US"
fileModeFileProperties = 0, "Percorso: %s\nDimensione: %s"
fileModeFolderProperties = 0, "Percorso: %s\nSottocartelle: %u\nNumero File: %u\nDimensione totale: %s"
fileModeMenu = 0, "Copia in "
fileModeMenu = 1, "Elimina"
fileModeMenu = 2, "Rinomina"
fileModeMenu = 3, "Crea Cartella"
fileModeMenu = 4, "Proprietà"
fileModeMenu = 5, "Chiudi"
fileModeMenu = 6, "Aggiungi ai Filtri del Percorso"
fileModeMenuMkDir = 0, "Nuovo"
folderMenuNew = 0, "Nuovo Backup"
helpFolder = 0, "[A] Seleziona [Y] Ripristina [X] Cancella [ZR] Upload [B] Chiudi"
helpSettings = 0, "[A] Attiva/Disattiva [X] Predefinite [B] Indietro"
helpTitle = 0, "[A] Seleziona [L][R] Jump [Y] Preferiti [X] Opzioni Titolo [B] Indietro"
helpUser = 0, "[A] Seleziona [Y] Dump di tutti i Salvataggi [X] Opzioni Utente"
holdingText = 0, "(Tieni Premuto) "
holdingText = 1, "(Continua a Premere) "
holdingText = 2, "(Ci sei quasi!) "
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "Tempo di Gioco: %02d:%02d"
infoStatus = 3, "Avvii Totali: %u"
infoStatus = 4, "Casa Editrice: %s"
infoStatus = 5, "Tipo Salvataggio: %s"
infoStatus = 6, "Indice della Cache: %u"
infoStatus = 7, "Utente: %s"
loadingStartPage = 0, "Caricamento..."
mainMenuExtras = 0, "Extras"
mainMenuSettings = 0, "Impost."
onlineErrorConnecting = 0, "Errore di Connessione!"
onlineNoUpdates = 0, "Nessun Aggiornamento Disponibile."
popAddedToPathFilter = 0, "'#%s#' aggiunto ai filtri del percorso."
popCPUBoostEnabled = 0, "CPU Boost Abilitato per ZIP."
popChangeOutputError = 0, "#%s# contiene caratteri illeciti o non-ASCII."
popChangeOutputFolder = 0, "#%s# cambiato in #%s#"
popDriveFailed = 0, "Impossibile avviare Google Drive."
popRemoteNotActive = 0, "Remote non è Disponibile"
popDriveStarted = 0, "Google Drive avviato con successo."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
popErrorCommittingFile = 0, "Errore durante il commiting del file da salvare!"
popFolderIsEmpty = 0, "La cartella è vuota!"
popProcessShutdown = 0, "#%s# spento con successo."
popSVIExported = 0, "SVI Esportato."
popSaveIsEmpty = 0, "Il salvataggio è vuoto!"
popTrashEmptied = 0, "Cestino Svuotato"
popZipIsEmpty = 0, "Il file ZIP è vuoto!"
saveDataBackupDeleted = 0, "#%s# è stato cancellato."
saveDataBackupMovedToTrash = 0, "#%s# è stato spostato nel cestino."
saveDataCreatedForUser = 0, "Salvataggio creato per %s!"
saveDataCreationFailed = 0, "Creazione salvataggio fallita!"
saveDataDeleteAllUser = 0, "*SEI SICURO DI VOLER CANCELLARE TUTTI I SALVATAGGI DI %s?*"
saveDataDeleteSuccess = 0, "Salvataggio di #%s# cancellato!"
saveDataExtendFailed = 0, "Estensione salvataggio fallita."
saveDataExtendSuccess = 0, "Salvataggio di #%s# esteso!"
saveDataIndexText = 0, "Indice di backup: "
saveDataNoneFound = 0, "Nessun Salvataggio trovato per #%s#!"
saveDataResetSuccess = 0, "Salvataggio di #%s# resettato!"
saveDataTypeText = 0, "Sistema"
saveDataTypeText = 1, "Account"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "Dispositivo"
saveDataTypeText = 4, "Temporanea"
saveDataTypeText = 5, "Cache"
saveDataTypeText = 6, "System BCAT"
saveTypeMainMenu = 0, "Disposit."
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
saveTypeMainMenu = 3, "Sistema"
saveTypeMainMenu = 4, "System BCAT"
saveTypeMainMenu = 5, "SysTemp Storagetem"
settingsMenu = 0, "Svuota Cestino"
settingsMenu = 1, "Controllo Aggiornamenti"
settingsMenu = 2, "Imposta cartella JKSV di Output"
settingsMenu = 3, "Modifica titoli in Blacklist"
settingsMenu = 4, "Cancella tutti i Salvataggi di Backup"
settingsMenu = 5, "Includi Salvataggi Dispositivo con Utenti: "
settingsMenu = 6, "Backup Automatico nel Ripristino: "
settingsMenu = 7, "Auto-Rinominazione Backups: "
settingsMenu = 8, "Overclock/CPU Boost: "
settingsMenu = 9, "Tieni premuto per eliminare: "
settingsMenu = 10, "Tieni premuto per ripristinare: "
settingsMenu = 11, "Tieni premuto per sovrascrivere: "
settingsMenu = 12, "Forza Montaggio: "
settingsMenu = 13, "Account System Saves: "
settingsMenu = 14, "Abilita scrittura su Salvataggi Sistema: "
settingsMenu = 15, "Usa comandi FS direttamente: "
settingsMenu = 16, "Esporta salvataggio in ZIP: "
settingsMenu = 17, "Forza utilizzo Inglese: "
settingsMenu = 18, "Abilita Cestino: "
settingsMenu = 19, "Tipo di ordinamento del Titolo: "
settingsMenu = 20, "Scala di Animazione: "
settingsOff = 0, "Off"
settingsOn = 0, ">On>"
sortType = 0, "Alfabetico"
sortType = 1, "Tempo di Gioco"
sortType = 2, "Ultima Partita"
swkbdEnterName = 0, "Inserisci nuovo nome"
swkbdExpandSize = 0, "Inserisci nuova dimensione in MB"
swkbdMkDir = 0, "Inserisci nome cartella"
swkbdNewSafeTitle = 0, "Inserisci una nuova cartella di output"
swkbdProcessID = 0, "Inserisci Process ID"
swkbdRename = 0, "Inserisci un nuovo nome per elemento"
swkbdSaveIndex = 0, "Inserisci l'Indice della Cache"
swkbdSetWorkDir = 0, "Inserisci un nuovo Percorso Output"
swkbdSysSavID = 0, "Inserisci System Save ID"
threadStatusAddingFileToZip = 0, "Aggiungi '#%s#' a ZIP..."
threadStatusCalculatingSaveSize = 0, "Calcolo dimensione salvataggio..."
threadStatusCheckingForUpdate = 0, "Controllo Aggiornamenti..."
threadStatusCompressingSaveForUpload = 0, "Compressione di #%s# per l'upload..."
threadStatusCopyingFile = 0, "Copiando '#%s#'..."
threadStatusCreatingSaveData = 0, "Creazione salvataggio per #%s#..."
threadStatusDecompressingFile = 0, "Decompressione '#%s#'..."
threadStatusDeletingFile = 0, "Cancellando..."
threadStatusDeletingSaveData = 0, "Cancellazione salvataggio di #%s#..."
threadStatusDeletingUpdate = 0, "Cancellazione dell'aggiornamento in sospeso..."
threadStatusDownloadingFile = 0, "Download di #%s#..."
threadStatusDownloadingUpdate = 0, "Download aggiornamento..."
threadStatusExtendingSaveData = 0, "Estensione Salvataggio per #%s#..."
threadStatusGetDirProps = 0, "Ottenimento le proprietà della cartella..."
threadStatusOpeningFolder = 0, "Apertura '#%s#'..."
threadStatusPackingJKSV = 0, "Scrittura del contenuto della cartella JKSV su ZIP..."
threadStatusResettingSaveData = 0, "Reset salvataggio..."
threadStatusSavingTranslations = 0, "Salvataggio del file master..."
threadStatusUploadingFile = 0, "Upload di #%s#..."
titleOptions = 0, "Informazioni"
titleOptions = 1, "Blacklist"
titleOptions = 2, "Cambia Cartella Output"
titleOptions = 3, "Apri in Modalità File"
titleOptions = 4, "Elimina tutti i Salvataggi di Backup"
titleOptions = 5, "Resetta Salvataggio"
titleOptions = 6, "Elimina Salvataggio"
titleOptions = 7, "Estendi Salvataggio"
titleOptions = 8, "Esporta SVI"
translationMainPage = 0, "Traduzione: "
userOptions = 0, "Dump di tutto per "
userOptions = 1, "Crea salvataggio"
userOptions = 2, "Crea tutti salvataggi"
userOptions = 3, "Cancella tutti salvataggi Utente"

View File

@ -1,215 +0,0 @@
author = 0, "NULL"
confirmBlacklist = 0, "ブラックリストに#%s#を追加してもよろしいですか?"
confirmCopy = 0, "#%s#を#%s#にコピーしてもよろしいですか?"
confirmCreateAllSaveData = 0, "このシステムで#%s#のすべてのセーブデータを作成してもよろしいですか?見つかったタイトルの数によっては、時間がかかる場合があります。"
confirmDelete = 0, "#%s#を削除してもよろしいですか? これは永続的です!"
confirmDeleteBackupsAll = 0, "全てのゲームのセーブバックアップを全て削除してもよろしいですか?"
confirmDeleteBackupsTitle = 0, "#%s#のすべてのセーブデータのバックアップを削除してもよろしいですか?"
confirmDeleteSaveData = 0, "警告: これにより、#%s#のセーブデータがシステムから消去されます。 これを実行してもよろしいですか?"
#CHANGED=============================================>
confirmDriveOverwrite = 0, "このバックアップをドライブからダウンロードすると、SDカードにあるバックアップが上書きされます。続行しますか"
#<====================================================
confirmOverwrite = 0, "#%s#を上書きしてもよろしいですか?"
confirmResetSaveData = 0, "警告: これにより、このゲームのセーブデータが、以前に実行されたことがないかのようにリセットされます。これを実行してもよろしいですか?"
confirmRestore = 0, "#%s#を復元してもよろしいですか?"
#CHANGED=============================================>
debugStatus = 0, "ユーザー数: "
debugStatus = 1, "現在のユーザー: "
debugStatus = 2, "現在のタイトル: "
debugStatus = 3, "安全なタイトル: "
debugStatus = 4, "ソートの種類: "
#<====================================================
dialogNo = 0, "いいえ [B]"
dialogOK = 0, "了解 [A]"
dialogYes = 0, "はい [A]"
extrasMenu = 0, "SDからSDブラウザ"
extrasMenu = 1, "BIS: ProdInfoF"
extrasMenu = 2, "BIS: Safe"
extrasMenu = 3, "BIS: System"
extrasMenu = 4, "BIS: User"
extrasMenu = 5, "保留中のアップデータを削除する"
extrasMenu = 6, "プロセスを終了します"
extrasMenu = 7, "マウントシステムSave"
extrasMenu = 8, "タイトルの再スキャン"
extrasMenu = 9, "マウントプロセスRomFS"
extrasMenu = 10, "JKSVフォルダをバックアップ"
extrasMenu = 11, "*[DEV]* 出力en-US"
fileModeFileProperties = 0, "パス: %s\n容量: %s"
fileModeFolderProperties = 0, "パス: %s\nサブフォルダ: %u\nファイル数: %u\n全体の大きさ: %s"
fileModeMenu = 0, "コピー先 "
fileModeMenu = 1, "削除"
fileModeMenu = 2, "リネーム"
fileModeMenu = 3, "ディレクトリ作成"
fileModeMenu = 4, "プロパティ"
fileModeMenu = 5, "閉じる"
fileModeMenu = 6, "パスフィルターに追加"
fileModeMenuMkDir = 0, "新規"
folderMenuNew = 0, "新規バックアップ"
#CHANGED=============================================>
helpFolder = 0, "[A] 選択 [Y] リストア [X] 削除 [ZR] アップロード [B] 閉じる"
#<====================================================
helpSettings = 0, "[A] トグル [X] デフォルト [B] 戻る"
helpTitle = 0, "[A] 選択 [L][R] ジャンプ [Y] お気に入り [X] タイトルオプション [B] 戻る"
helpUser = 0, "[A] 選択 [X] ユーザー設定"
holdingText = 0, "(所有) "
holdingText = 1, "(保持し続けます) "
holdingText = 2, "(もうすぐです!) "
#CHANGED=============================================>
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "プレイ時間: %02d:%02d"
infoStatus = 3, "起動回数: %u"
infoStatus = 4, "出版社: %s"
infoStatus = 5, "セーブの種類: %s"
infoStatus = 6, "キャッシュインデックス: %u"
infoStatus = 7, "ユーザー: %s"
#<=====================================================
loadingStartPage = 0, "読み込み中..."
mainMenuExtras = 0, "エクストラ"
mainMenuSettings = 0, "設定"
onlineErrorConnecting = 0, "接続エラー!"
onlineNoUpdates = 0, "利用可能なアップデートはありません。"
popAddedToPathFilter = 0, "'#%s#' パスフィルターに追加されました。"
popCPUBoostEnabled = 0, "ZIPでCPUブーストが有効になっています。"
popChangeOutputError = 0, "#%s# は、不正な文字または非ASCII文字が含まれています。"
popChangeOutputFolder = 0, "#%s# から #%s# に変更"
#CHANGED=============================================>
popDriveFailed = 0, "Google Driveの起動に失敗しました。"
popRemoteNotActive = 0, "Remoteドライブは使用できません"
popDriveStarted = 0, "Google Driveが正常に起動しました。"
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
#<====================================================
popErrorCommittingFile = 0, "保存するファイルのコミット中にエラーが発生しました!"
popFolderIsEmpty = 0, "フォルダは空です!"
popProcessShutdown = 0, "#%s# 正常にシャットダウンしました。"
#CHANGED=============================================>
popSVIExported = 0, "SVIをエクスポートしました。"
#<====================================================
popSaveIsEmpty = 0, "セーブデータは空です!"
popTrashEmptied = 0, "ゴミ箱を空にする"
popZipIsEmpty = 0, "ZIPファイルは空です!"
saveDataBackupDeleted = 0, "#%s#が削除されました。"
saveDataBackupMovedToTrash = 0, "#%s#はゴミ箱に移動されました"
saveDataCreatedForUser = 0, "#%s#用に作成されたデータを保存する!"
saveDataCreationFailed = 0, "セーブデータの作成に失敗しました!"
saveDataDeleteAllUser = 0, "#%s#のすべての保存データを削除してもよろしいですか?*"
saveDataDeleteSuccess = 0, "#%s#のセーブデータは削除されました!"
saveDataExtendFailed = 0, "セーブデータの拡張に失敗しました。"
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"
saveTypeMainMenu = 0, "デバイス"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "キャッシュ"
saveTypeMainMenu = 3, "システム"
saveTypeMainMenu = 4, "システム BCAT"
saveTypeMainMenu = 5, "システマティックストレージ機器"
settingsMenu = 0, "ゴミ箱を空にする"
settingsMenu = 1, "アップデートを確認する"
settingsMenu = 2, "JKSVセーブデータ保存出力フォルダを設定する"
settingsMenu = 3, "ブラックリストに載っているタイトルを編集する"
settingsMenu = 4, "すべての保存バックアップを削除する"
settingsMenu = 5, "ユーザーと一緒にデバイスのセーブデータを含める: "
settingsMenu = 6, "復元時の自動バックアップ: "
settingsMenu = 7, "自動名前バックアップ: "
settingsMenu = 8, "オーバークロック/CPUブースト: "
settingsMenu = 9, "削除するために保持: "
settingsMenu = 10, "保持して復元: "
settingsMenu = 11, "上書きするために保持: "
settingsMenu = 12, "フォースマウント: "
settingsMenu = 13, "アカウントシステムセーブデータ: "
settingsMenu = 14, "システムセーブデータへの書き込みを有効にする: "
settingsMenu = 15, "FSコマンドを直接使用する: "
settingsMenu = 16, "セーブデータをZIPにエクスポート: "
settingsMenu = 17, "英語を強制的に使用する: "
settingsMenu = 18, "ごみ箱を有効にする: "
settingsMenu = 19, "タイトルの並べ替えタイプ: "
settingsMenu = 20, "アニメーションスケール: "
settingsOff = 0, "オフ"
settingsOn = 0, ">オン>"
sortType = 0, "アルファベット順"
sortType = 1, "プレイ時間"
sortType = 2, "最後にプレイ"
swkbdEnterName = 0, "新しい名前を入力してください"
swkbdExpandSize = 0, "新しいサイズをMBで入力"
swkbdMkDir = 0, "フォルダ名を入力してください"
swkbdNewSafeTitle = 0, "新規出力先フォルダを入力してください"
swkbdProcessID = 0, "プロセスIDを入力してください"
swkbdRename = 0, "アイテムの新しい名前を入力してください"
swkbdSaveIndex = 0, "キャッシュインデックスを入力してください"
swkbdSetWorkDir = 0, "新しい出力パスを入力してください"
swkbdSysSavID = 0, "システムセーブIDを入力してください"
threadStatusAddingFileToZip = 0, "#%s#をZIPに追加中..."
#CHANGED=============================================>
threadStatusCalculatingSaveSize = 0, "保存データサイズの算出中..."
#<====================================================
threadStatusCheckingForUpdate = 0, "アップデートの確認中..."
#CHANGED=============================================>
threadStatusCompressingSaveForUpload = 0, "アップロードのために #%s# を圧縮中..."
#<====================================================
threadStatusCopyingFile = 0, "#%s#をコピーしています..."
threadStatusCreatingSaveData = 0, "#%s#のセームデータの作成中..."
threadStatusDecompressingFile = 0, "#%s#の解凍中..."
threadStatusDeletingFile = 0, "削除中..."
threadStatusDeletingSaveData = 0, "#%s#のセーブデータを削除中..."
threadStatusDeletingUpdate = 0, "保留中のアップデータを削除中..."
#CHANGED=============================================>
threadStatusDownloadingFile = 0, "ダウンロード中 #%s#..."
#<====================================================
threadStatusDownloadingUpdate = 0, "アップデータをダウンロード中..."
threadStatusExtendingSaveData = 0, "#%s#のセーブデータを拡張中..."
threadStatusGetDirProps = 0, "フォルダプロパティの取得中..."
threadStatusOpeningFolder = 0, "#%s#を開き中..."
threadStatusPackingJKSV = 0, "JKSVフォルダの内容をZIPに書き込み中..."
threadStatusResettingSaveData = 0, "セーブデータをリストアしています..."
threadStatusSavingTranslations = 0, "ファイルマスタの保存中..."
#CHANGED=============================================>
threadStatusUploadingFile = 0, "アップロード中 #%s#..."
#<====================================================
titleOptions = 0, "インフォメーション"
titleOptions = 1, "ブラックリスト"
titleOptions = 2, "出力フォルダを変更する"
titleOptions = 3, "ファイルモードで開く"
titleOptions = 4, "すべてのセーブデータバックアップを削除する"
titleOptions = 5, "セーブデータをリセット"
titleOptions = 6, "セーブデータを削除"
titleOptions = 7, "セーブデータを拡張"
#CHANGED=============================================>
titleOptions = 8, "エクスポートSVI"
#<====================================================
translationMainPage = 0, "翻訳: "
userOptions = 0, "すべてをダンプする "
userOptions = 1, "セーブデータを作成"
userOptions = 2, "全てのセーブデータを作成"
userOptions = 3, "全てのユーザーセーブデータを削除"

View File

@ -1,171 +0,0 @@
author = 0, "NULL"
confirmBlacklist = 0, "블랙리스트에 #%s#을(를) 추가하겠습니까?"
confirmCopy = 0, "#%s#을(를) #%s#에 복사하겠습니까?"
confirmCreateAllSaveData = 0, "이 시스템에서 #%s#에 대한 모든 저장 데이터를 생성하겠습니까? 검색된 타이틀 수에 따라 시간이 걸릴 수 있습니다."
confirmDelete = 0, "#%s#을(를) 삭제하겠습니까? *영구적입니다*!"
confirmDeleteBackupsAll = 0, "모든 게임에 대한 *모든* 저장 백업을 삭제하겠습니까?"
confirmDeleteBackupsTitle = 0, "#%s#에 대한 모든 백업 백업을 삭제하겠습니까?"
confirmDeleteSaveData = 0, "경고*: 이렇게 하면 #%s#에 대한 저장 데이터가 *시스템에서* 지워집니다. 정말 하겠습니까?"
confirmDriveOverwrite = 0, "드라이브에서 이 백업을 다운로드하면 SD 카드에 있는 백업을 덮어씁니다. 계속합니까?"
confirmOverwrite = 0, "#%s#을(를) 덮어쓰시겠습니까?"
confirmResetSaveData = 0, "경고*: 이렇게 하면 이 게임의 저장 데이터가 이전에 실행되지 않은 것처럼 *리셋됩니다*. 정말 하겠습니까?"
confirmRestore = 0, "#%s#을(를) 복원하겠습니까?"
debugStatus = 0, "사용자 수: "
debugStatus = 1, "현자 사용자: "
debugStatus = 2, "현재 제목: "
debugStatus = 3, "안전 제목: "
debugStatus = 4, "정렬 유형: "
dialogNo = 0, "아니오 [B]"
dialogOK = 0, "확인 [A]"
dialogYes = 0, "예 [A]"
extrasMenu = 0, "SD에서 SD 브라우저로"
extrasMenu = 1, "BIS: ProdInfoF"
extrasMenu = 2, "BIS: 안전"
extrasMenu = 3, "BIS: 시스템"
extrasMenu = 4, "BIS: 사용자"
extrasMenu = 5, "보류 중인 업데이트 제거"
extrasMenu = 6, "프로세스 종료"
extrasMenu = 7, "시스템 저장 인식"
extrasMenu = 8, "제목 다시 검색"
extrasMenu = 9, "프로세스 RomFS 인식"
extrasMenu = 10, "JKSV 폴더 백업"
extrasMenu = 11, "*[DEV]* 출력 en-US"
fileModeFileProperties = 0, "경로: %s\n크기: %s"
fileModeFolderProperties = 0, "경로: %s\n하위 폴더: %u\n파일 수: %u\n전체 크기: %s"
fileModeMenu = 0, "에게 복사 "
fileModeMenu = 1, "삭제"
fileModeMenu = 2, "이름 바꾸기"
fileModeMenu = 3, "폴더 만들기"
fileModeMenu = 4, "속성"
fileModeMenu = 5, "닫기"
fileModeMenu = 6, "경로 필터에 추가"
fileModeMenuMkDir = 0, "새로 만들기"
folderMenuNew = 0, "새 백업"
helpFolder = 0, "[A] 선택 [Y] 복원 [X] 삭제 [ZR] 업로드 [B] 닫기"
helpSettings = 0, "[A] 전환 [X] 기본 [B] 뒤로가기"
helpTitle = 0, "[A] 선택 [L][R] 점프 [Y] 즐겨찾기 [X] 제목 옵션 [B] 뒤로가기"
helpUser = 0, "[A] 선택 [Y] 모든 세이브 덤프 [X] 사용자 옵션"
holdingText = 0, "(길게 누르기) "
holdingText = 1, "(계속 누르기) "
holdingText = 2, "(거의 완료!) "
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "즐긴 시간: %02d:%02d"
infoStatus = 3, "총 실행 수: %u"
infoStatus = 4, "발행자: %s"
infoStatus = 5, "저장 유형: %s"
infoStatus = 6, "캐시 인덱스: %u"
infoStatus = 7, "사용자: %s"
infoStatus = 9, ""
loadingStartPage = 0, "로드 중..."
mainMenuExtras = 0, "추가"
mainMenuSettings = 0, "설정"
onlineErrorConnecting = 0, "연결 오류!"
onlineNoUpdates = 0, "사용 가능한 업데이트가 없습니다."
popAddedToPathFilter = 0, "'#%s#'이(가) 경로 필터에 추가되었습니다."
popCPUBoostEnabled = 0, "ZIP를 위한 CPU 부스트가 활성화되었습니다."
popChangeOutputError = 0, "#%s#에 잘못된 또는 ASCII가 아닌 문자가 포함되어 있습니다."
popChangeOutputFolder = 0, "#%s#이(가) #%s#로 변경되었습니다."
popDriveFailed = 0, "구글 드라이브 시작에 실패했습니다."
popRemoteNotActive = 0, "구글 드라이브를 사용할 수 없습니다."
popDriveStarted = 0, "구글 드라이브가 성공적으로 시작되었습니다."
popWebdavStarted = 0, "Webdav가 성공적으로 시작되었습니다."
popWebdavFailed =, 0, "Webdav를 시작하지 못했습니다."
popErrorCommittingFile = 0, "저장할 파일을 커밋하는 동안 오류가 발생했습니다!"
popFolderIsEmpty = 0, "폴더가 비어 있습니다!"
popProcessShutdown = 0, "#%s#이(가) 성공적으로 종료되었습니다."
popSVIExported = 0, "SVI를 내보냈습니다."
popSaveIsEmpty = 0, "저장 데이터가 비어 있습니다!"
popTrashEmptied = 0, "휴지통이 비었습니다."
popZipIsEmpty = 0, "ZIP 파일이 비어 있습니다!"
saveDataBackupDeleted = 0, "#%s#이(가) 삭제되었습니다."
saveDataBackupMovedToTrash = 0, "#%s#이(가) 휴지통으로 이동되었습니다."
saveDataCreatedForUser = 0, "%s에 대해 생성된 데이터 저장!"
saveDataCreationFailed = 0, "저장 데이터 생성 실패!"
saveDataDeleteAllUser = 0, "*%s에 대한 모든 저장 데이터를 삭제하겠습니까?*"
saveDataDeleteSuccess = 0, "#%s#에 대한 저장 데이터가 삭제되었습니다!"
saveDataExtendFailed = 0, "저장 데이터 확장에 실패했습니다."
saveDataExtendSuccess = 0, "#%s#에 대한 데이터 저장이 확장되었습니다!"
saveDataNoneFound = 0, "#%s#에 대한 저장을 찾을 수 없습니다!"
saveDataResetSuccess = 0, "#%s# 재설정을 위해 저장합니다!"
saveDataTypeText = 0, "시스템"
saveDataTypeText = 1, "계정"
saveDataTypeText = 2, "BCAT"
saveDataTypeText = 3, "장치"
saveDataTypeText = 4, "임시"
saveDataTypeText = 5, "캐시"
saveDataTypeText = 6, "시스템 BCAT"
saveTypeMainMenu = 0, "장치"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "캐시"
saveTypeMainMenu = 3, "시스템"
saveTypeMainMenu = 4, "시스템 BCAT"
saveTypeMainMenu = 5, "SysTemp 스토리지템"
settingsMenu = 0, "휴지통 비우기"
settingsMenu = 1, "업데이트 확인"
settingsMenu = 2, "JKSV 저장 출력 폴더 설정"
settingsMenu = 3, "블랙리스트에 있는 제목 편집"
settingsMenu = 4, "모든 저장 백업 삭제"
settingsMenu = 5, "사용자와 함께 장치 저장 포함: "
settingsMenu = 6, "복원 시 자동 백업: "
settingsMenu = 7, "자동 이름 백업: "
settingsMenu = 8, "오버클럭/CPU 부스트: "
settingsMenu = 9, "삭제하려면 길게 누르기: "
settingsMenu = 10, "복원하려면 길게 누르기: "
settingsMenu = 11, "덮어쓰려면 길게 누르기: "
settingsMenu = 12, "강제 인식: "
settingsMenu = 13, "계정 시스템 저장: "
settingsMenu = 14, "시스템 저장에 쓰기 활성화: "
settingsMenu = 15, "FS 명령을 직접 사용: "
settingsMenu = 16, "저장된 파일을 ZIP으로 내보내기: "
settingsMenu = 17, "강제 영어 사용: "
settingsMenu = 18, "휴지통 활성화: "
settingsMenu = 19, "제목 정렬 유형: "
settingsMenu = 20, "애니메이션 스케일: "
settingsOff = 0, "끔"
settingsOn = 0, ">켬>"
sortType = 0, "알파벳"
sortType = 1, "즐긴 시간"
sortType = 2, "마지막 실행"
swkbdEnterName = 0, "새 이름 입력"
swkbdExpandSize = 0, "새 MB 크기 입력"
swkbdMkDir = 0, "폴더 이름 입력"
swkbdNewSafeTitle = 0, "새 출력 폴더 입력"
swkbdProcessID = 0, "프로세스 ID 입력"
swkbdRename = 0, "항목의 새 이름을 입력"
swkbdSaveIndex = 0, "캐시 인덱스 입력"
swkbdSetWorkDir = 0, "새 출력 경로 입력"
swkbdSysSavID = 0, "시스템 저장 ID 입력"
threadStatusAddingFileToZip = 0, "'#%s#'을(를) ZIP에 추가하는 중..."
threadStatusCalculatingSaveSize = 0, "저장 데이터 크기 계산 중..."
threadStatusCheckingForUpdate = 0, "업데이트 확인 중..."
threadStatusCompressingSaveForUpload = 0, "업로드를 위해 #%s# 압축 중..."
threadStatusCopyingFile = 0, "'#%s#' 복사 중..."
threadStatusCreatingSaveData = 0, "#%s#에 대한 저장 데이터 생성 중..."
threadStatusDecompressingFile = 0, "'#%s#' 압축 해제 중..."
threadStatusDeletingFile = 0, "삭제 중..."
threadStatusDeletingSaveData = 0, "#%s#에 대한 저장 데이터 삭제 중..."
threadStatusDeletingUpdate = 0, "대기 중인 업데이트 삭제 중..."
threadStatusDownloadingFile = 0, "#%s# 다운로드 중..."
threadStatusDownloadingUpdate = 0, "업데이트 다운로드 중..."
threadStatusExtendingSaveData = 0, "#%s#에 대한 저장 데이터 확장 중..."
threadStatusGetDirProps = 0, "폴더 속성 가져오기..."
threadStatusOpeningFolder = 0, "'#%s#'을(를) 여는 중..."
threadStatusPackingJKSV = 0, "JKSV 폴더 내용을 ZIP에 쓰는 중..."
threadStatusResettingSaveData = 0, "저장 데이터 재설정 중..."
threadStatusSavingTranslations = 0, "마스터 파일 저장 중..."
threadStatusUploadingFile = 0, "#%s# 업로드 중..."
titleOptions = 0, "정보"
titleOptions = 1, "블랙리스트"
titleOptions = 2, "출력 폴더 변경"
titleOptions = 3, "파일 모드에서 열기"
titleOptions = 4, "모든 저장 백업 삭제"
titleOptions = 5, "저장 데이터 재설정"
titleOptions = 6, "저장 데이터 삭제"
titleOptions = 7, "저장 데이터 확장"
titleOptions = 8, "SVI 내보내기"
translationMainPage = 0, "번역: "
userOptions = 0, "에 대해 모두 덤프 "
userOptions = 1, "저장 데이터 생성"
userOptions = 2, "모든 저장 데이터 생성"
userOptions = 3, "모든 사용자 저장 삭제"

View File

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,156 +0,0 @@
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#?"
dialogNo = 0, "No [B]"
dialogOK = 0, "OK [A]"
dialogYes = 0, "Yes [A]"
extrasMenu = 0, "SD to SD Browser"
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 = 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..."
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"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "Cache"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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"

View File

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,171 +0,0 @@
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?"
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]"
extrasMenu = 0, "SD to SD Browser"
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 = 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 [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 [Y] Dump All Saves [X] User Options"
holdingText = 0, "(Hold) "
holdingText = 1, "(Keep Holding) "
holdingText = 2, "(Almost There!) "
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"
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#"
popDriveFailed = 0, "Failed to start Google Drive."
popRemoteNotActive = 0, "Remote is not available"
popDriveStarted = 0, "Google Drive started successfully."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
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."
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!"
saveDataNoneFound = 0, "No saves found for #%s#!"
saveDataResetSuccess = 0, "Save for #%s# reset!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
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..."
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"
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"
titleOptions = 8, "Export SVI"
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"

View File

@ -1,170 +0,0 @@
author = 0, "NULL"
confirmBlacklist = 0, "是否确定要将#%s#添加到您的黑名单中?"
confirmCopy = 0, "是否确定要将#%s#复制到#%s#"
confirmCreateAllSaveData = 0, "是否确定要在此系统上为#%s#创建所有存档数据这可能需要一些时间具体取决于找到的Title的数量。"
confirmDelete = 0, "是否确定要删除#%s#*这是永久的*"
confirmDeleteBackupsAll = 0, "是否确定要删除您所有游戏的*所有*存档备份?"
confirmDeleteBackupsTitle = 0, "是否确定要删除#%s#的所有存档备份?"
confirmDeleteSaveData = 0, "*警告*:这*将会*从*系统*中删除#%s#的存档数据。您确定要这样做吗?"
confirmDriveOverwrite = 0, "下载这个备份将会覆盖您的SD卡上的备份。是否继续"
confirmOverwrite = 0, "是否确定要覆盖#%s#?"
confirmResetSaveData = 0, "*警告*:这*将会*重置此游戏的存档数据,就像以前从未运行过一样。您确定要这样做吗?"
confirmRestore = 0, "是否确定要还原#%s#"
debugStatus = 0, "用户数量: "
debugStatus = 1, "当前用户: "
debugStatus = 2, "当前Title: "
debugStatus = 3, "安全Title: "
debugStatus = 4, "排序方式: "
dialogNo = 0, "否 [B]"
dialogOK = 0, "确定 [A]"
dialogYes = 0, "是 [A]"
extrasMenu = 0, "文件管理器"
extrasMenu = 1, "BIS分区ProdInfoF"
extrasMenu = 2, "BIS分区Safe"
extrasMenu = 3, "BIS分区System"
extrasMenu = 4, "BIS分区User"
extrasMenu = 5, "删除挂起的更新"
extrasMenu = 6, "终止进程"
extrasMenu = 7, "挂载系统存档"
extrasMenu = 8, "重新扫描Title"
extrasMenu = 9, "挂载进程RomFS"
extrasMenu = 10, "备份JKSV文件夹"
extrasMenu = 11, "*[开发者]* 输出en-US"
fileModeFileProperties = 0, "路径:%s\n大小%s"
fileModeFolderProperties = 0, "路径:%s\n子目录%u\n文件数量%u\n总大小%s"
fileModeMenu = 0, "复制到"
fileModeMenu = 1, "删除"
fileModeMenu = 2, "重命名"
fileModeMenu = 3, "新建文件夹"
fileModeMenu = 4, "属性"
fileModeMenu = 5, "关闭"
fileModeMenu = 6, "添加到路径过滤器"
fileModeMenuMkDir = 0, "新建"
folderMenuNew = 0, "新建备份"
helpFolder = 0, "[A] 选择 [Y] 还原 [X] 删除 [ZR] 上传 [B] 关闭"
helpSettings = 0, "[A] 切换 [X] 恢复默认 [B] 返回"
helpTitle = 0, "[A] 选择 [L][R] 翻页 [Y] 收藏 [X] Title选项 [B] 返回"
helpUser = 0, "[A] 选择 [Y] 转储所有存档 [X] 用户选项"
holdingText = 0, "(按住)"
holdingText = 1, "(继续按住)"
holdingText = 2, "(快好了!)"
infoStatus = 0, "TID: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "游玩时间: %02d:%02d"
infoStatus = 3, "启动次数: %u"
infoStatus = 4, "发行商: %s"
infoStatus = 5, "存档类型: %s"
infoStatus = 6, "缓存索引: %u"
infoStatus = 7, "用户: %s"
loadingStartPage = 0, "加载中..."
mainMenuExtras = 0, "附加功能"
mainMenuSettings = 0, "系统设置"
onlineErrorConnecting = 0, "连接错误!"
onlineNoUpdates = 0, "没有可用的更新。"
popAddedToPathFilter = 0, "'#%s#'已添加到路径过滤器。"
popCPUBoostEnabled = 0, "为ZIP压缩启用CPU超频。"
popChangeOutputError = 0, "#%s#包含非法或者非ASCII的字符。"
popChangeOutputFolder = 0, "#%s#更改到#%s#"
popDriveFailed = 0, "Google Drive启动失败。"
popRemoteNotActive = 0, "Remote不可用。"
popDriveStarted = 0, "Google Drive启动成功。"
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
popErrorCommittingFile = 0, "提交要保存的文件时出错!"
popFolderIsEmpty = 0, "文件夹为空!"
popProcessShutdown = 0, "#%s#已成功关闭。"
popSVIExported = 0, "SVI文件已导出"
popSaveIsEmpty = 0, "存档数据为空!"
popTrashEmptied = 0, "回收站已清空"
popZipIsEmpty = 0, "ZIP文件为空"
saveDataBackupDeleted = 0, "#%s#已被删除。"
saveDataBackupMovedToTrash = 0, "#%s#已被移到回收站。"
saveDataCreatedForUser = 0, "%s的存档数据已创建"
saveDataCreationFailed = 0, "存档数据创建失败!"
saveDataDeleteAllUser = 0, "*确定要删除%s的所有存档数据吗*"
saveDataDeleteSuccess = 0, "#%s#的存档数据已删除!"
saveDataExtendFailed = 0, "扩展存档数据失败。"
saveDataExtendSuccess = 0, "#%s#的存档数据已扩展!"
saveDataNoneFound = 0, "没有找到#%s#的存档!"
saveDataResetSuccess = 0, "#%s#的存档已重置!"
saveDataTypeText = 0, "系统存档"
saveDataTypeText = 1, "用户存档"
saveDataTypeText = 2, "BCAT存档"
saveDataTypeText = 3, "设备存档"
saveDataTypeText = 4, "临时存档"
saveDataTypeText = 5, "缓存存档"
saveDataTypeText = 6, "系统BCAT存档"
saveTypeMainMenu = 0, "设备"
saveTypeMainMenu = 1, "BCAT"
saveTypeMainMenu = 2, "缓存"
saveTypeMainMenu = 3, "系统"
saveTypeMainMenu = 4, "系统BCAT"
saveTypeMainMenu = 5, "临时"
settingsMenu = 0, "清空回收站"
settingsMenu = 1, "检查更新"
settingsMenu = 2, "设置JKSV的存档输出文件夹"
settingsMenu = 3, "编辑Title黑名单"
settingsMenu = 4, "删除所有存档备份"
settingsMenu = 5, "用户存档中包含设备存档:"
settingsMenu = 6, "恢复时自动备份:"
settingsMenu = 7, "自动命名备份:"
settingsMenu = 8, "CPU超频"
settingsMenu = 9, "按住以删除:"
settingsMenu = 10, "按住以恢复:"
settingsMenu = 11, "按住以覆盖:"
settingsMenu = 12, "强制挂载:"
settingsMenu = 13, "用户系统存档:"
settingsMenu = 14, "允许写入系统存档:"
settingsMenu = 15, "直接使用FS命令"
settingsMenu = 16, "导出存档到ZIP文件"
settingsMenu = 17, "强制使用英语:"
settingsMenu = 18, "启用回收站:"
settingsMenu = 19, "Title排序方式"
settingsMenu = 20, "动画比例:"
settingsOff = 0, "关"
settingsOn = 0, ">开>"
sortType = 0, "按软件名"
sortType = 1, "按游玩时间"
sortType = 2, "按最近游玩"
swkbdEnterName = 0, "请输入新的名称"
swkbdExpandSize = 0, "请输入新的大小单位MB"
swkbdMkDir = 0, "请输入文件夹名称"
swkbdNewSafeTitle = 0, "请输入新的输出文件夹"
swkbdProcessID = 0, "请输入进程ID"
swkbdRename = 0, "请输入新的项目名称"
swkbdSaveIndex = 0, "请输入缓存索引"
swkbdSetWorkDir = 0, "请输入新的输出路径"
swkbdSysSavID = 0, "请输入系统存档ID"
threadStatusAddingFileToZip = 0, "正在添加'#%s#'到ZIP文件..."
threadStatusCalculatingSaveSize = 0, "正在计算存档数据大小..."
threadStatusCheckingForUpdate = 0, "正在检查更新..."
threadStatusCompressingSaveForUpload = 0, "正在压缩#%s#以便上传..."
threadStatusCopyingFile = 0, "正在复制'#%s#'..."
threadStatusCreatingSaveData = 0, "正在创建#%s#的存档数据..."
threadStatusDecompressingFile = 0, "正在解压'#%s#'..."
threadStatusDeletingFile = 0, "正在删除..."
threadStatusDeletingSaveData = 0, "正在删除#%s#的存档数据..."
threadStatusDeletingUpdate = 0, "正在删除挂起的更新..."
threadStatusDownloadingFile = 0, "正在下载#%s#..."
threadStatusDownloadingUpdate = 0, "正在下载更新..."
threadStatusExtendingSaveData = 0, "正在扩展#%s#的存档数据..."
threadStatusGetDirProps = 0, "正在获取文件夹属性..."
threadStatusOpeningFolder = 0, "正在打开'#%s#'..."
threadStatusPackingJKSV = 0, "正在写入JKSV文件夹的内容到ZIP文件..."
threadStatusResettingSaveData = 0, "正在重置存档数据..."
threadStatusSavingTranslations = 0, "Saving the file master..."
threadStatusUploadingFile = 0, "正在上传#%s#..."
titleOptions = 0, "信息"
titleOptions = 1, "黑名单"
titleOptions = 2, "更改输出文件夹"
titleOptions = 3, "在文件管理器中打开"
titleOptions = 4, "删除所有存档备份"
titleOptions = 5, "重置存档数据"
titleOptions = 6, "删除存档数据"
titleOptions = 7, "扩展存档数据"
titleOptions = 8, "导出SVI文件"
translationMainPage = 0, "翻译:"
userOptions = 0, "转储所有存档:"
userOptions = 1, "创建存档数据"
userOptions = 2, "创建所有游戏的存档数据"
userOptions = 3, "删除所有用户存档"

View File

@ -1,171 +0,0 @@
author = 0, "Leo"
confirmBlacklist = 0, "是否確定要將#%s#加入黑名單?"
confirmCopy = 0, "是否確定要將#%s#複製到#%s#?"
confirmCreateAllSaveData = 0, "是否確定要複製系統內所有遊戲進度並新增到使用者#%s#帳號內? 完成此操作的等待時間將取決於系統內的遊戲進度檔案數量."
confirmDelete = 0, "是否確定要刪除#%s#? *此為永久性刪除!*"
confirmDeleteBackupsAll = 0, "是否確定要刪除你備份所有遊戲的 *全部* 存檔進度?"
confirmDeleteBackupsTitle = 0, "是否確定要刪除#%s#的全部存檔進度?"
confirmDeleteSaveData = 0, "*注意*: 此操作 *將會* 完整刪除#%s# *在主機系統內* 的存檔進度. 請再次確認是否要繼續進行?"
confirmDriveOverwrite = 0, "準備將主機的儲存進度備份至記憶卡,將會覆蓋記憶卡上原有的備份檔案. 請再次確認是否要繼續進行?"
confirmOverwrite = 0, "是否確定要覆寫#%s#?"
confirmResetSaveData = 0, "*注意*: 此操作 *將會* 重置歸零此遊戲的存檔進度,像是從未執行過. 請再次確認是否要繼續進行?"
confirmRestore = 0, "是否確定要還原#%s#?"
debugStatus = 0, "使用者數量: "
debugStatus = 1, "目前使用者: "
debugStatus = 2, "目前的Title: "
debugStatus = 3, "Safe Title: "
debugStatus = 4, "排序準則: "
dialogNo = 0, "否 [B]"
dialogOK = 0, "確定 [A]"
dialogYes = 0, "是 [A]"
extrasMenu = 0, "檔案管理視窗"
extrasMenu = 1, "BIS: ProdInfoF"
extrasMenu = 2, "BIS: Safe"
extrasMenu = 3, "BIS: System"
extrasMenu = 4, "BIS: User"
extrasMenu = 5, "移除系統更新通知"
extrasMenu = 6, "終止指定程序"
extrasMenu = 7, "掛載系統存檔"
extrasMenu = 8, "重新掃瞄Titles"
extrasMenu = 9, "掛載RomFS程序"
extrasMenu = 10, "備份JKSV資料夾"
extrasMenu = 11, "*[DEV]* 使用英文介面"
fileModeFileProperties = 0, "路徑: %s\n大小: %s"
fileModeFolderProperties = 0, "路徑: %s\n子目錄: %u\n檔案總數: %u\n檔案容量: %s"
fileModeMenu = 0, "複製到"
fileModeMenu = 1, "刪除"
fileModeMenu = 2, "改檔名"
fileModeMenu = 3, "新建資料夾"
fileModeMenu = 4, "屬性"
fileModeMenu = 5, "關閉"
fileModeMenu = 6, "新增至路徑篩選器"
fileModeMenuMkDir = 0, "新建"
folderMenuNew = 0, "新建目錄"
helpFolder = 0, "[A] 選定 [Y] 還原 [X] 刪除 [ZR] 上傳 [B] 返回"
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: %016lX"
infoStatus = 1, "SID: %016lX"
infoStatus = 2, "遊玩時間: %02d:%02d"
infoStatus = 3, "啟動次數: %u"
infoStatus = 4, "發行商: %s"
infoStatus = 5, "存檔類型: %s"
infoStatus = 6, "快取索引: %u"
infoStatus = 7, "使用者: %s"
loadingStartPage = 0, "加載中…"
mainMenuExtras = 0, "附加設定"
mainMenuSettings = 0, "系統設定"
onlineErrorConnecting = 0, "連線失敗!"
onlineNoUpdates = 0, "目前沒有可用的更新版本!"
popAddedToPathFilter = 0, "'#%s#' 已新增至路徑篩選器."
popCPUBoostEnabled = 0, "壓縮ZIP時將啟用CPU超頻."
popChangeOutputError = 0, "#%s# 包含非法或者非ASCII字元."
popChangeOutputFolder = 0, "#%s# 更改到 #%s#"
popDriveFailed = 0, "無法啟用Google雲端硬碟."
popRemoteNotActive = 0, "沒有可用的Remote雲端硬碟."
popDriveStarted = 0, "Google雲端硬碟已正確啟用."
popWebdavStarted = 0, "Webdav started successfully."
popWebdavFailed =, 0, "Failed to start Webdav."
popErrorCommittingFile = 0, "提交檔案進行儲存時發生錯誤!"
popFolderIsEmpty = 0, "資料夾內沒有檔案!"
popProcessShutdown = 0, "#%s# 程序已關閉."
popSVIExported = 0, "已匯出SVI."
popSaveIsEmpty = 0, "沒有找到存檔進度!"
popTrashEmptied = 0, "資源回收筒已清空"
popZipIsEmpty = 0, "ZIP壓縮檔內沒有檔案!"
saveDataBackupDeleted = 0, "#%s#已被刪除."
saveDataBackupMovedToTrash = 0, "#%s#已被移動至資源回收筒."
saveDataCreatedForUser = 0, "存檔已新增至%s!"
saveDataCreationFailed = 0, "存檔新增失敗!"
saveDataDeleteAllUser = 0, "*是否確認要刪除%s使用者的所有遊戲進度存檔?*"
saveDataDeleteSuccess = 0, "#%s#的進度存檔已刪除!"
saveDataExtendFailed = 0, "無法擴充此遊戲的進度儲存空間."
saveDataExtendSuccess = 0, "#%s#的進度存檔儲存空間已擴充!"
saveDataIndexText = 0, "存檔索引:"
saveDataNoneFound = 0, "沒有#%s#的進度存檔!"
saveDataResetSuccess = 0, "#%s#的進度存檔已重置!"
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"
saveTypeMainMenu = 3, "System"
saveTypeMainMenu = 4, "System BCAT"
saveTypeMainMenu = 5, "SysTemp Storagetem"
settingsMenu = 0, "清空資源回收筒"
settingsMenu = 1, "檢查程式更新"
settingsMenu = 2, "設定JKSV進度存檔匯出的資料夾"
settingsMenu = 3, "編輯Titles黑名單"
settingsMenu = 4, "刪除所有進度存檔"
settingsMenu = 5, "包含綁定主機的使用者進度存檔: "
settingsMenu = 6, "還原前自動備份: "
settingsMenu = 7, "備份時自動命名: "
settingsMenu = 8, "CPU超頻: "
settingsMenu = 9, "長按確認後刪除: "
settingsMenu = 10, "長按確認後還原: "
settingsMenu = 11, "長按確認後覆寫: "
settingsMenu = 12, "強制掛載: "
settingsMenu = 13, "使用者系統進度存檔: "
settingsMenu = 14, "允許存取系統進度存檔: "
settingsMenu = 15, "直接使用FS命令: "
settingsMenu = 16, "匯出存檔時壓縮為ZIP: "
settingsMenu = 17, "強制顯示為英文: "
settingsMenu = 18, "啟用資源回收筒: "
settingsMenu = 19, "Title排序模式: "
settingsMenu = 20, "彈出視窗延遲: "
settingsOff = 0, "關"
settingsOn = 0, ">開>"
sortType = 0, "依名稱字母順序"
sortType = 1, "依遊玩時間長度"
sortType = 2, "依最後遊玩時間"
swkbdEnterName = 0, "請輸入新的名稱"
swkbdExpandSize = 0, "輸入新的大小(MB)"
swkbdMkDir = 0, "請輸入資料夾名稱"
swkbdNewSafeTitle = 0, "輸入新的匯出目錄名稱"
swkbdProcessID = 0, "請輸入程序ID"
swkbdRename = 0, "請輸入item的新名稱"
swkbdSaveIndex = 0, "請輸入快取索引"
swkbdSetWorkDir = 0, "請輸入新的匯出路徑"
swkbdSysSavID = 0, "請輸入系統存檔ID"
threadStatusAddingFileToZip = 0, "正在將'#%s#'的存檔壓縮為ZIP..."
threadStatusCalculatingSaveSize = 0, "正在計算進度檔案大小..."
threadStatusCheckingForUpdate = 0, "檢查是否有可用更新..."
threadStatusCompressingSaveForUpload = 0, "正在壓縮#%s#準備上傳..."
threadStatusCopyingFile = 0, "正在複製'#%s#'..."
threadStatusCreatingSaveData = 0, "正在新增#%s#的存檔進度..."
threadStatusDecompressingFile = 0, "'#%s#'存檔正在解壓縮..."
threadStatusDeletingFile = 0, "刪除中..."
threadStatusDeletingSaveData = 0, "正在刪除#%s#的存檔進度.."
threadStatusDeletingUpdate = 0, "正在刪除系統更新..."
threadStatusDownloadingFile = 0, "正在下載#%s#..."
threadStatusDownloadingUpdate = 0, "正在下載更新版本..."
threadStatusExtendingSaveData = 0, "正在擴充#%s#的存檔空間..."
threadStatusGetDirProps = 0, "正在取得資料夾屬性資訊..."
threadStatusOpeningFolder = 0, "正在開啟'#%s#'資料夾..."
threadStatusPackingJKSV = 0, "正在將JKSV資料夾壓縮為ZIP..."
threadStatusResettingSaveData = 0, "正在重置遊戲存檔進度..."
threadStatusSavingTranslations = 0, "正在儲存file master..."
threadStatusUploadingFile = 0, "正在上傳#%s#..."
titleOptions = 0, "詳細資訊"
titleOptions = 1, "設為黑名單"
titleOptions = 2, "變更匯出檔案資料夾"
titleOptions = 3, "以檔案管理器開啟"
titleOptions = 4, "刪除所有進度存檔"
titleOptions = 5, "重置進度存檔"
titleOptions = 6, "刪除進度存檔"
titleOptions = 7, "擴充存檔空間"
titleOptions = 8, "匯出SVI"
translationMainPage = 0, "翻譯:"
userOptions = 0, "備份使用者全部存檔:"
userOptions = 1, "新增遊戲存檔進度"
userOptions = 2, "新增所有遊戲存檔進度"
userOptions = 3, "刪除使用者全部存檔"

View File

@ -1,561 +0,0 @@
#include <json-c/json.h>
#include <string>
#include <switch.h>
#include <unordered_map>
#include "cfg.h"
#include "data.h"
#include "file.h"
#include "type.h"
#include "ui.h"
#include "util.h"
std::unordered_map<std::string, bool> cfg::config;
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;
std::string cfg::webdavOrigin, cfg::webdavBasePath, cfg::webdavUser, cfg::webdavPassword;
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},
{"driveRefreshToken", 19},
};
const std::string _true_ = "true", _false_ = "false";
bool cfg::isBlacklisted(uint64_t tid)
{
for (uint64_t &bid : cfg::blacklist)
if (tid == bid)
return true;
return false;
}
//Has to be threaded to be compatible with ui::confirm
void cfg::addTitleToBlacklist(void *a)
{
threadInfo *t = (threadInfo *)a;
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
uint64_t tid = d->tid;
cfg::blacklist.push_back(tid);
for (data::user &u : data::users)
{
for (unsigned i = 0; i < u.titleInfo.size(); i++)
if (u.titleInfo[i].tid == tid)
u.titleInfo.erase(u.titleInfo.begin() + i);
}
ui::ttlRefresh();
cfg::saveConfig();
t->finished = true;
}
void cfg::removeTitleFromBlacklist(uint64_t tid)
{
for (unsigned i = 0; i < cfg::blacklist.size(); i++)
{
if (cfg::blacklist[i] == tid)
cfg::blacklist.erase(cfg::blacklist.begin() + i);
}
data::loadUsersTitles(false);
ui::ttlRefresh();
cfg::saveConfig();
}
bool cfg::isFavorite(uint64_t tid)
{
for (uint64_t &fid : cfg::favorites)
if (tid == fid)
return true;
return false;
}
static int getFavoriteIndex(uint64_t tid)
{
for (unsigned i = 0; i < cfg::favorites.size(); i++)
{
if (tid == cfg::favorites[i])
return i;
}
return -1;
}
void cfg::addTitleToFavorites(uint64_t tid)
{
if (cfg::isFavorite(tid))
{
int rem = getFavoriteIndex(tid);
cfg::favorites.erase(cfg::favorites.begin() + rem);
}
else
cfg::favorites.push_back(tid);
data::sortUserTitles();
ui::ttlRefresh();
cfg::saveConfig();
}
bool cfg::isDefined(uint64_t tid)
{
for (auto &def : pathDefs)
if (def.first == tid)
return true;
return false;
}
void cfg::pathDefAdd(uint64_t tid, const std::string &newPath)
{
data::titleInfo *t = data::getTitleInfoByTID(tid);
std::string oldSafe = t->safeTitle;
std::string tmp = util::safeString(newPath);
if (!tmp.empty())
{
pathDefs[tid] = tmp;
t->safeTitle = tmp;
std::string oldOutput = fs::getWorkDir() + oldSafe;
std::string newOutput = fs::getWorkDir() + tmp;
rename(oldOutput.c_str(), newOutput.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT,
ui::getUICString("popChangeOutputFolder", 0),
oldSafe.c_str(),
tmp.c_str());
}
else
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popChangeOutputError", 0), newPath.c_str());
}
std::string cfg::getPathDefinition(uint64_t tid)
{
return pathDefs[tid];
}
void cfg::addPathToFilter(uint64_t tid, const std::string &_p)
{
char outpath[128];
sprintf(outpath, "sdmc:/config/JKSV/0x%016lX_filter.txt", tid);
FILE *filters = fopen(outpath, "a");
fprintf(filters, "%s\n", _p.c_str());
fclose(filters);
}
void cfg::resetConfig()
{
cfg::config["incDev"] = false;
cfg::config["autoBack"] = true;
cfg::config["ovrClk"] = false;
cfg::config["holdDel"] = true;
cfg::config["holdRest"] = true;
cfg::config["holdOver"] = true;
cfg::config["forceMount"] = true;
cfg::config["accSysSave"] = false;
cfg::config["sysSaveWrite"] = false;
cfg::config["directFsCmd"] = false;
cfg::config["zip"] = true;
cfg::config["langOverride"] = false;
cfg::config["trashBin"] = true;
cfg::config["autoName"] = false;
cfg::sortType = cfg::ALPHA;
ui::animScale = 3.0f;
cfg::config["autoUpload"] = false;
}
static inline bool textToBool(const std::string &_txt)
{
return _txt == _true_ ? true : false;
}
static inline std::string boolToText(bool _b)
{
return _b ? _true_ : _false_;
}
static inline std::string sortTypeText()
{
switch (cfg::sortType)
{
case cfg::ALPHA:
return "ALPHA";
break;
case cfg::MOST_PLAYED:
return "MOST_PLAYED";
break;
case cfg::LAST_PLAYED:
return "LAST_PLAYED";
break;
}
return "";
}
static void loadWorkDirLegacy()
{
if (fs::fileExists(workDirLegacy))
{
char tmp[256];
memset(tmp, 0, 256);
FILE *getDir = fopen(workDirLegacy, "r");
fgets(tmp, 256, getDir);
fclose(getDir);
std::string tmpStr = tmp;
util::stripChar('\n', tmpStr);
util::stripChar('\r', tmpStr);
fs::setWorkDir(tmpStr);
fs::delfile(workDirLegacy);
}
}
static void loadConfigLegacy()
{
std::string legacyCfgPath = fs::getWorkDir() + "cfg.bin";
if (fs::fileExists(legacyCfgPath))
{
FILE *oldCfg = fopen(legacyCfgPath.c_str(), "rb");
uint64_t cfgIn = 0;
fread(&cfgIn, sizeof(uint64_t), 1, oldCfg);
fread(&cfg::sortType, 1, 1, oldCfg);
fread(&ui::animScale, sizeof(float), 1, oldCfg);
if (ui::animScale == 0)
ui::animScale = 3.0f;
fclose(oldCfg);
cfg::config["incDev"] = cfgIn >> 63 & 1;
cfg::config["autoBack"] = cfgIn >> 62 & 1;
cfg::config["ovrClk"] = cfgIn >> 61 & 1;
cfg::config["holdDel"] = cfgIn >> 60 & 1;
cfg::config["holdRest"] = cfgIn >> 59 & 1;
cfg::config["holdOver"] = cfgIn >> 58 & 1;
cfg::config["forceMount"] = cfgIn >> 57 & 1;
cfg::config["accSysSave"] = cfgIn >> 56 & 1;
cfg::config["sysSaveWrite"] = cfgIn >> 55 & 1;
cfg::config["directFsCmd"] = cfgIn >> 53 & 1;
cfg::config["zip"] = cfgIn >> 51 & 1;
cfg::config["langOverride"] = cfgIn >> 50 & 1;
cfg::config["trashBin"] = cfgIn >> 49 & 1;
fs::delfile(legacyCfgPath.c_str());
}
}
static void loadFavoritesLegacy()
{
std::string legacyFavPath = fs::getWorkDir() + "favorites.txt";
if (fs::fileExists(legacyFavPath))
{
fs::dataFile fav(legacyFavPath);
while (fav.readNextLine(false))
cfg::favorites.push_back(strtoul(fav.getLine().c_str(), NULL, 16));
fav.close();
fs::delfile(legacyFavPath);
}
}
static void loadBlacklistLegacy()
{
std::string legacyBlPath = fs::getWorkDir() + "blacklist.txt";
if (fs::fileExists(legacyBlPath))
{
fs::dataFile bl(legacyBlPath);
while (bl.readNextLine(false))
cfg::blacklist.push_back(strtoul(bl.getLine().c_str(), NULL, 16));
bl.close();
fs::delfile(legacyBlPath);
}
}
static void loadTitleDefsLegacy()
{
std::string titleDefLegacy = fs::getWorkDir() + "titleDefs.txt";
if (fs::fileExists(titleDefLegacy))
{
fs::dataFile getPaths(titleDefLegacy);
while (getPaths.readNextLine(true))
{
uint64_t tid = strtoul(getPaths.getName().c_str(), NULL, 16);
pathDefs[tid] = getPaths.getNextValueStr();
}
getPaths.close();
fs::delfile(titleDefLegacy);
}
}
//Oops
static void loadTitleDefs()
{
if (fs::fileExists(titleDefPath))
{
fs::dataFile getPaths(titleDefPath);
while (getPaths.readNextLine(true))
{
uint64_t tid = strtoul(getPaths.getName().c_str(), NULL, 16);
pathDefs[tid] = getPaths.getNextValueStr();
}
}
}
static void loadDriveConfig()
{
// Start Google Drive
fs::dirList cfgList("/config/JKSV/", true);
std::string clientSecretPath;
for (unsigned i = 0; i < cfgList.getCount(); i++)
{
std::string itemName = cfgList.getItem(i);
if (itemName.find("client_secret") != itemName.npos)
{
clientSecretPath = "/config/JKSV/" + cfgList.getItem(i);
break;
}
}
if (!clientSecretPath.empty())
{
json_object *installed, *clientID, *clientSecret, *driveJSON = json_object_from_file(clientSecretPath.c_str());
if (driveJSON)
{
if (json_object_object_get_ex(driveJSON, "installed", &installed))
{
if (json_object_object_get_ex(installed, "client_id", &clientID) &&
json_object_object_get_ex(installed, "client_secret", &clientSecret))
{
cfg::driveClientID = json_object_get_string(clientID);
cfg::driveClientSecret = json_object_get_string(clientSecret);
}
}
json_object_put(driveJSON);
}
}
// End Google Drive
// Webdav
json_object *webdavJSON = json_object_from_file("/config/JKSV/webdav.json");
json_object *origin, *basepath, *username, *password;
if (webdavJSON)
{
if (json_object_object_get_ex(webdavJSON, "origin", &origin))
{
cfg::webdavOrigin = json_object_get_string(origin);
}
if (json_object_object_get_ex(webdavJSON, "basepath", &basepath))
{
cfg::webdavBasePath = json_object_get_string(basepath);
}
if (json_object_object_get_ex(webdavJSON, "username", &username))
{
cfg::webdavUser = json_object_get_string(username);
}
if (json_object_object_get_ex(webdavJSON, "password", &password))
{
cfg::webdavPassword = json_object_get_string(password);
}
json_object_put(webdavJSON);
}
}
void cfg::loadConfig()
{
cfg::resetConfig();
loadWorkDirLegacy();
loadConfigLegacy();
loadFavoritesLegacy();
loadBlacklistLegacy();
loadTitleDefsLegacy();
loadTitleDefs();
if (fs::fileExists(cfgPath))
{
fs::dataFile cfgRead(cfgPath);
while (cfgRead.readNextLine(true))
{
std::string varName = cfgRead.getName();
if (cfgStrings.find(varName) != cfgStrings.end())
{
switch (cfgStrings[varName])
{
case 0:
fs::setWorkDir(cfgRead.getNextValueStr());
break;
case 1:
cfg::config["incDev"] = textToBool(cfgRead.getNextValueStr());
break;
case 2:
cfg::config["autoBack"] = textToBool(cfgRead.getNextValueStr());
break;
case 3:
cfg::config["ovrClk"] = textToBool(cfgRead.getNextValueStr());
break;
case 4:
cfg::config["holdDel"] = textToBool(cfgRead.getNextValueStr());
break;
case 5:
cfg::config["holdRest"] = textToBool(cfgRead.getNextValueStr());
break;
case 6:
cfg::config["holdOver"] = textToBool(cfgRead.getNextValueStr());
break;
case 7:
cfg::config["forceMount"] = textToBool(cfgRead.getNextValueStr());
break;
case 8:
cfg::config["accSysSave"] = textToBool(cfgRead.getNextValueStr());
break;
case 9:
cfg::config["sysSaveWrite"] = textToBool(cfgRead.getNextValueStr());
break;
case 10:
cfg::config["directFsCmd"] = textToBool(cfgRead.getNextValueStr());
break;
case 11:
cfg::config["zip"] = textToBool(cfgRead.getNextValueStr());
break;
case 12:
cfg::config["langOverride"] = 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 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 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 19:
cfg::driveRefreshToken = cfgRead.getNextValueStr();
break;
case 20:
cfg::config["autoUpload"] = textToBool(cfgRead.getNextValueStr());
break;
default:
break;
}
}
}
}
loadDriveConfig();
}
static void savePathDefs()
{
FILE *pathOut = fopen(titleDefPath, "w");
for (auto &p : pathDefs)
fprintf(pathOut, "0x%016lX = \"%s\"\n", p.first, p.second.c_str());
fclose(pathOut);
}
void cfg::saveConfig()
{
FILE *cfgOut = fopen("sdmc:/config/JKSV/JKSV.cfg", "w");
fprintf(cfgOut, "#JKSV config.\nworkDir = \"%s\"\n\n", fs::getWorkDir().c_str());
fprintf(cfgOut, "includeDeviceSaves = %s\n", boolToText(cfg::config["incDev"]).c_str());
fprintf(cfgOut, "autoBackup = %s\n", boolToText(cfg::config["autoBack"]).c_str());
fprintf(cfgOut, "autoName = %s\n", boolToText(cfg::config["autoName"]).c_str());
fprintf(cfgOut, "overclock = %s\n", boolToText(cfg::config["ovrClk"]).c_str());
fprintf(cfgOut, "holdToDelete = %s\n", boolToText(cfg::config["holdDel"]).c_str());
fprintf(cfgOut, "holdToRestore = %s\n", boolToText(cfg::config["holdRest"]).c_str());
fprintf(cfgOut, "holdToOverwrite = %s\n", boolToText(cfg::config["holdOver"]).c_str());
fprintf(cfgOut, "forceMount = %s\n", boolToText(cfg::config["forceMount"]).c_str());
fprintf(cfgOut, "accountSystemSaves = %s\n", boolToText(cfg::config["accSysSaves"]).c_str());
fprintf(cfgOut, "allowSystemSaveWrite = %s\n", boolToText(cfg::config["sysSaveWrite"]).c_str());
fprintf(cfgOut, "directFSCommands = %s\n", boolToText(cfg::config["directFsCmd"]).c_str());
fprintf(cfgOut, "exportToZIP = %s\n", boolToText(cfg::config["zip"]).c_str());
fprintf(cfgOut, "languageOverride = %s\n", boolToText(cfg::config["langOverride"]).c_str());
fprintf(cfgOut, "enableTrashBin = %s\n", boolToText(cfg::config["trashBin"]).c_str());
fprintf(cfgOut, "titleSortType = %s\n", sortTypeText().c_str());
fprintf(cfgOut, "animationScale = %f\n", ui::animScale);
if (!cfg::driveRefreshToken.empty())
fprintf(cfgOut, "driveRefreshToken = %s\n", cfg::driveRefreshToken.c_str());
if (!cfg::favorites.empty())
{
fprintf(cfgOut, "\n#favorites\n");
for (uint64_t &f : cfg::favorites)
fprintf(cfgOut, "favorite = 0x%016lX\n", f);
}
if (!cfg::blacklist.empty())
{
fprintf(cfgOut, "\n#blacklist\n");
for (uint64_t &b : cfg::blacklist)
fprintf(cfgOut, "blacklist = 0x%016lX\n", b);
}
fclose(cfgOut);
if (!pathDefs.empty())
savePathDefs();
}

View File

@ -1,101 +0,0 @@
#include <string>
#include <vector>
#include <curl/curl.h>
#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 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;
}
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();
curl_easy_setopt(handle, CURLOPT_URL, _url.c_str());
curl_easy_setopt(handle, CURLOPT_HTTPGET, 1);
curl_easy_setopt(handle, CURLOPT_USERAGENT, "JKSV");
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeDataString);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &ret);
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(handle, CURLOPT_TIMEOUT, 15);
if(headers)
{
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, writeHeaders);
curl_easy_setopt(handle, CURLOPT_HEADERDATA, headers);
}
if(curl_easy_perform(handle) != CURLE_OK)
ret.clear();//JIC
curl_easy_cleanup(handle);
return ret;
}
size_t writeDataBin(uint8_t *buff, size_t sz, size_t cnt, void *u)
{
size_t sizeIn = sz * cnt;
std::vector<uint8_t> *binData = (std::vector<uint8_t> *)u;
binData->reserve(sizeIn);
binData->insert(binData->end(), buff, buff + sizeIn);
return sizeIn;
}
bool curlFuncs::getBinURL(std::vector<uint8_t> *out, const std::string& _url)
{
bool ret = false;
CURL *handle = curl_easy_init();
curl_easy_setopt(handle, CURLOPT_URL, _url.c_str());
curl_easy_setopt(handle, CURLOPT_HTTPGET, 1);
curl_easy_setopt(handle, CURLOPT_USERAGENT, "JKSV");
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeDataBin);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, out);
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1);
curl_easy_setopt(handle, CURLOPT_TIMEOUT, 15);
if(curl_easy_perform(handle) == CURLE_OK)
ret = true;
curl_easy_cleanup(handle);
return ret;
}

View File

@ -1,649 +1,290 @@
#include <algorithm>
#include <array>
#include <cstdio>
#include <cstring>
#include <ctime>
#include <memory>
#include <string>
#include <string_view>
#include <switch.h>
#include <unordered_map>
#include <vector>
#include <string>
#include <cstring>
#include <fstream>
#include <algorithm>
#include <cstdio>
#include <switch.h>
#include "cfg.h"
#include "data.h"
#include "file.h"
#include "type.h"
#include "util.h"
namespace
{
/// @brief This is the string used for when a publisher isn't found in the NACP.
constexpr std::string_view STRING_UNKOWN_AUTHOR = "Someone?";
/// @brief This array holds the order in which to scan save data space IDs since the all pseudo value from libnx doesn't seem to work.
constexpr std::array<FsSaveDataSpaceId, 7> ORDER_SAVE_DATA_SPACES = {FsSaveDataSpaceId_System,
FsSaveDataSpaceId_User,
FsSaveDataSpaceId_SdSystem,
FsSaveDataSpaceId_Temporary,
FsSaveDataSpaceId_SdUser,
FsSaveDataSpaceId_ProperSystem,
FsSaveDataSpaceId_SafeMode};
/// @brief This saves whether or not the System BCAT user was pushed.
bool s_systemBCATPushed = false;
/// @brief This saves whether or not the Temporary save user was pushed.
bool s_temporaryPushed = false;
} // namespace
/// @brief External variables I used to track selected user/title.
int selUser = 0, selData = 0;
/// @brief This vector holds the user instances.
std::vector<data::user> data::users;
/// @brief System language. I don't know why this is here in data?
SetLanguage data::sysLang;
/// @brief This is the map of titleInfo.
std::unordered_map<uint64_t, data::titleInfo> data::titles;
//Sorts titles by sortType
//Sorts titles sort-of alphabetically
static struct
{
bool operator()(const data::userTitleInfo &a, const data::userTitleInfo &b)
bool operator()(data::titledata& a, data::titledata& b)
{
for(unsigned i = 0; i < a.getTitle().length(); i++)
{
//Favorites override EVERYTHING
if (cfg::isFavorite(a.tid) != cfg::isFavorite(b.tid))
return cfg::isFavorite(a.tid);
switch (cfg::sortType)
{
case cfg::ALPHA:
{
std::string titleA = data::getTitleNameByTID(a.tid);
std::string titleB = data::getTitleNameByTID(b.tid);
uint32_t pointA, pointB;
for (unsigned i = 0, j = 0; i < titleA.length();)
{
ssize_t aCnt = decode_utf8(&pointA, (const uint8_t *)&titleA.data()[i]);
ssize_t bCnt = decode_utf8(&pointB, (const uint8_t *)&titleB.data()[j]);
pointA = tolower(pointA), pointB = tolower(pointB);
if (pointA != pointB)
return pointA < pointB;
i += aCnt;
j += bCnt;
}
}
break;
case cfg::MOST_PLAYED:
return a.playStats.playtime > b.playStats.playtime;
break;
case cfg::LAST_PLAYED:
return a.playStats.last_timestamp_user > b.playStats.last_timestamp_user;
break;
}
return false;
int charA = tolower(a.getTitle().c_str()[i]), charB = tolower(b.getTitle().c_str()[i]);
if(charA != charB)
return charA < charB;
}
return false;
}
} sortTitles;
//Returns -1 for new
static int getUserIndex(AccountUid id)
static int getUserIndex(const u128& id)
{
u128 nId = util::accountUIDToU128(id);
for (unsigned i = 0; i < data::users.size(); i++)
if (data::users[i].getUID128() == nId)
for(unsigned i = 0; i < data::users.size(); i++)
{
if(data::users[i].getUID() == id)
return i;
}
return -1;
}
static inline bool accountSystemSaveCheck(const FsSaveDataInfo &_inf)
namespace data
{
if (_inf.save_data_type == FsSaveDataType_System && util::accountUIDToU128(_inf.uid) != 0 &&
!cfg::config["accSysSave"])
return false;
titledata curData;
user curUser;
std::vector<icn> icons;
std::vector<user> users;
bool sysSave = false;
return true;
}
//Minimal init/test to avoid loading and creating things I don't need
static bool testMount(const FsSaveDataInfo &_inf)
{
bool ret = false;
if (!cfg::config["forceMount"])
return true;
if ((ret = fs::mountSave(_inf)))
fs::unmountSave();
return ret;
}
/// @brief This version of the function uses the title/application ID to pull the data from the system.
/// @param titleID Title/Application ID of the title to add.
static void add_title_to_list(uint64_t titleID)
{
// This is the output size of the control data.
uint64_t dataSize = 0;
// This is the size of the icon.
size_t iconSize = 0;
// Nacp language entry pointer.
NacpLanguageEntry *entry = nullptr;
// Try to read the control data directly into the map.
Result nsError = nsGetApplicationControlData(NsApplicationControlSource_Storage,
titleID,
&data::titles[titleID].data,
sizeof(NsApplicationControlData),
&dataSize);
// At this point, regardless, the title should exist in the map. Using a reference from here on out.
data::titleInfo &info = data::titles[titleID];
// Calc icon size. Not sure this is really needed?
iconSize = dataSize - sizeof(NacpStruct);
// If that failed, run the backup routine and bail.
if (R_FAILED(nsError) || dataSize < sizeof(info.data.nacp) || iconSize <= 0 ||
R_FAILED(nacpGetLanguageEntry(&info.data.nacp, &entry)))
void loadDataInfo()
{
// Clear the NACP.
std::memset(&info.data.nacp, 0x00, sizeof(NacpStruct));
icn defIcon;
defIcon.load(0, "romfs:/img/icn/icnDefault.png");
icons.push_back(defIcon);
// Set the title and publisher.
info.title = util::getIDStr(titleID);
info.author = STRING_UNKOWN_AUTHOR;
for(unsigned i = 0; i < users.size(); i++)
users[i].titles.clear();
// Check if the title has a path defined in the config.
if (cfg::isDefined(titleID))
users.clear();
Result res = 0;
FsSaveDataIterator saveIt;
size_t total = 0;
FsSaveDataInfo info;
res = fsOpenSaveDataIterator(&saveIt, FsSaveDataSpaceId_All);
if(R_FAILED(res))
{
info.safeTitle = cfg::getPathDefinition(titleID);
}
else
{
info.safeTitle = util::getIDStr(titleID);
printf("SaveDataIterator Failed\n");
return;
}
// Create the icon.
std::string idHex = util::getIDStrLower(titleID);
info.icon = util::createIconGeneric(idHex.c_str(), 32, true);
// Bail. Do not continue. We're done.
return;
}
else
{
// Check to make sure the title isn't blank. If it is, use English.
if (std::char_traits<char>::length(entry->name) == 0)
while(true)
{
info.title = info.data.nacp.lang[SetLanguage_ENUS].name;
}
else
{
info.title = entry->name;
}
res = fsSaveDataIteratorRead(&saveIt, &info, 1, &total);
if(R_FAILED(res) || total == 0)
break;
// Check the same for author/publisher.
if (std::char_traits<char>::length(entry->author) == 0)
{
info.author = info.data.nacp.lang[SetLanguage_ENUS].author;
}
else
{
info.author = entry->author;
}
// Load the icon from the control data.
info.icon = gfx::texMgr->textureLoadFromMem(IMG_FMT_JPG, info.data.icon, iconSize);
// Make sure to save that the title has valid control data.
info.hasControlData = true;
}
// The following is universal whether the title has control data or not.
// Set the safe path title. Note: I hate the second else if statement, but screw it. Rewrite avoids this kind of stuff.
if (cfg::isDefined(titleID))
{
info.safeTitle = cfg::getPathDefinition(titleID);
}
else if ((info.safeTitle = util::safeString(entry->name)) == "")
{
info.safeTitle = util::getIDStr(titleID);
}
// Favorite check.
if (cfg::isFavorite(titleID))
{
info.fav = true;
}
}
/// @brief Adds a title to the map using the application ID and cached control data.
/// @param titleID Application ID of the title.
/// @param data Reference to the data to use.
static void add_title_to_list(uint64_t titleID, NsApplicationControlData &data)
{
// Start by memcpy'ing the data over.
std::memcpy(&data::titles[titleID].data, &data, sizeof(NsApplicationControlData));
// Since this function is always being fed cached data, we're going to assume everything else is good.
}
static inline bool titleIsLoaded(uint64_t titleID)
{
return data::titles.find(titleID) != data::titles.end();
}
static void loadUserAccounts(void)
{
// Total accounts listed.
int total = 0;
// Switch has eight accounts max.
AccountUid accounts[8] = {0};
if (R_FAILED(accountListAllUsers(accounts, 8, &total)))
{
// Rewrite logs this.
return;
}
for (int i = 0; i < total; i++)
{
// Maybe to do: This looks stupid. Overload constructors?
data::users.emplace_back(accounts[i], "", "");
}
}
//This can load titles installed without having save data
static void loadTitlesFromRecords()
{
NsApplicationRecord nsRecord;
int32_t entryCount = 0, recordOffset = 0;
while (R_SUCCEEDED(nsListApplicationRecord(&nsRecord, 1, recordOffset++, &entryCount)) && entryCount > 0)
{
if (!titleIsLoaded(nsRecord.application_id))
{
add_title_to_list(nsRecord.application_id);
}
}
}
static void import_svi_files(void)
{
// This is the path used. JKSV master was written before fslib.
std::string sviPath = fs::getWorkDir() + "svi";
// Get the listing and check to make sure there was actually something in it.
fs::dirList sviList(sviPath);
if (sviList.getCount() <= 0)
{
// Just return and don't do anything.
return;
}
// Loop through the listing and load them all.
for (unsigned int i = 0; i < sviList.getCount(); i++)
{
// Full path to the file.
std::string fullPath = sviPath + "/" + sviList.getItem(i);
// Grab the size of the SVI before continuing.
size_t sviSize = fs::fsize(fullPath);
// Application ID
uint64_t applicationID = 0;
// Language entry.
NacpLanguageEntry *entry = nullptr;
// Icon size.
size_t iconSize = 0;
// Open the file and read the application ID.
std::FILE *sviFile = std::fopen(sviPath.c_str(), "rb");
std::fread(&applicationID, 1, sizeof(uint64_t), sviFile);
// If it already exists in the map, just continue.
if (titleIsLoaded(applicationID))
{
std::fclose(sviFile);
continue;
}
// Read the NACP data into the map directly.
std::fread(&data::titles[applicationID].data.nacp, 1, sizeof(NacpStruct), sviFile);
// Calculate the icon size and read that too. The ControlData has memory set aside for the icon anyway.
iconSize = fs::fsize(fullPath) - (sizeof(uint64_t) + sizeof(NacpStruct));
std::fread(&data::titles[applicationID].data.icon, 1, iconSize, sviFile);
// Think I should be safe to use a reference now?
data::titleInfo &info = data::titles[applicationID];
// Setup the title stuff.
if (R_FAILED(nacpGetLanguageEntry(&info.data.nacp, &entry)))
{
// Default to English.
info.title = info.data.nacp.lang[SetLanguage_ENUS].name;
info.author = info.data.nacp.lang[SetLanguage_ENUS].author;
}
else
{
info.title = entry->name;
info.author = entry->author;
}
// Safe path.
if (cfg::isDefined(applicationID))
{
info.safeTitle = cfg::getPathDefinition(applicationID);
}
else if ((info.safeTitle = util::safeString(info.title)).empty())
{
info.safeTitle = util::getIDStr(applicationID);
}
// Favorite
if (cfg::isFavorite(applicationID))
{
info.fav = true;
}
// Just going to assume this is good.
info.icon = gfx::texMgr->textureLoadFromMem(IMG_FMT_JPG, info.data.icon, iconSize);
}
}
bool data::loadUsersTitles(bool clearUsers)
{
static unsigned systemUserCount = 4;
FsSaveDataInfoReader it;
FsSaveDataInfo info;
s64 total = 0;
loadTitlesFromRecords();
import_svi_files();
//Clear titles
for (data::user &u : data::users)
{
u.titleInfo.clear();
}
if (clearUsers)
{
systemUserCount = 4;
for (data::user &u : data::users)
{
u.delIcon();
}
data::users.clear();
loadUserAccounts();
s_systemBCATPushed = false;
s_temporaryPushed = false;
users.emplace_back(util::u128ToAccountUID(3), ui::getUIString("saveTypeMainMenu", 0), "Device");
users.emplace_back(util::u128ToAccountUID(2), ui::getUIString("saveTypeMainMenu", 1), "BCAT");
users.emplace_back(util::u128ToAccountUID(5), ui::getUIString("saveTypeMainMenu", 2), "Cache");
users.emplace_back(util::u128ToAccountUID(0), ui::getUIString("saveTypeMainMenu", 3), "System");
}
for (unsigned i = 0; i < 7; i++)
{
if (R_FAILED(fsOpenSaveDataInfoReader(&it, ORDER_SAVE_DATA_SPACES.at(i))))
continue;
while (R_SUCCEEDED(fsSaveDataInfoReaderRead(&it, &info, 1, &total)) && total != 0)
{
uint64_t tid = 0;
if (info.save_data_type == FsSaveDataType_System || info.save_data_type == FsSaveDataType_SystemBcat)
tid = info.system_save_data_id;
else
tid = info.application_id;
if (!titleIsLoaded(tid))
if((info.SaveDataType == FsSaveDataType_SaveData) || sysSave)
{
add_title_to_list(tid);
}
//Don't bother with this stuff
if (cfg::isBlacklisted(tid) || !accountSystemSaveCheck(info) || !testMount(info))
continue;
switch (info.save_data_type)
{
case FsSaveDataType_Bcat:
info.uid = util::u128ToAccountUID(2);
break;
case FsSaveDataType_Device:
info.uid = util::u128ToAccountUID(3);
break;
case FsSaveDataType_SystemBcat:
info.uid = util::u128ToAccountUID(4);
if (!s_systemBCATPushed)
int u = getUserIndex(info.userID);
if(u == -1)
{
user newUser;
if(newUser.init(info.userID) || (sysSave && newUser.initNoChk(info.userID)))
{
++systemUserCount;
s_systemBCATPushed = true;
users.emplace_back(util::u128ToAccountUID(4),
ui::getUIString("saveTypeMainMenu", 4),
"System BCAT");
users.push_back(newUser);
u = getUserIndex(info.userID);
titledata newData;
if(newData.init(info) && newData.isMountable(newUser.getUID()))
{
users[u].titles.push_back(newData);
}
}
break;
case FsSaveDataType_Cache:
info.uid = util::u128ToAccountUID(5);
break;
case FsSaveDataType_Temporary:
info.uid = util::u128ToAccountUID(6);
if (!s_temporaryPushed)
}
else
{
titledata newData;
if(newData.init(info) && newData.isMountable(users[u].getUID()))
{
++systemUserCount;
s_temporaryPushed = true;
users.emplace_back(util::u128ToAccountUID(6),
ui::getUIString("saveTypeMainMenu", 5),
"Temporary");
users[u].titles.push_back(newData);
}
break;
}
}
int u = getUserIndex(info.uid);
if (u == -1)
{
users.emplace(data::users.end() - systemUserCount, info.uid, "", "");
u = getUserIndex(info.uid);
}
PdmPlayStatistics playStats;
if (info.save_data_type == FsSaveDataType_Account || info.save_data_type == FsSaveDataType_Device)
pdmqryQueryPlayStatisticsByApplicationIdAndUserAccountId(info.application_id,
info.uid,
false,
&playStats);
else
memset(&playStats, 0, sizeof(PdmPlayStatistics));
users[u].addUserTitleInfo(tid, &info, &playStats);
}
fsSaveDataInfoReaderClose(&it);
fsSaveDataIteratorClose(&saveIt);
for(unsigned i = 0; i < users.size(); i++)
std::sort(users[i].titles.begin(), users[i].titles.end(), sortTitles);
curUser = users[0];
}
if (cfg::config["incDev"])
void exit()
{
//Get reference to device save user
unsigned devPos = getUserIndex(util::u128ToAccountUID(3));
data::user &dev = data::users[devPos];
for (unsigned i = 0; i < devPos; i++)
for(unsigned i = 0; i < users.size(); i++)
texDestroy(users[i].userIcon);
for(unsigned i = 0; i < icons.size(); i++)
icons[i].deleteData();
}
void icn::load(const uint64_t& _id, const uint8_t *jpegData, const size_t& jpegSize)
{
titleID = _id;
iconTex = texLoadJPEGMem(jpegData, jpegSize);
}
void icn::load(const uint64_t& _id, const std::string& _png)
{
titleID = _id;
iconTex = texLoadPNGFile(_png.c_str());
}
int findIcnIndex(const uint64_t& titleID)
{
for(unsigned i = 0; i < icons.size(); i++)
{
//Not needed but makes this easier to read
data::user &u = data::users[i];
u.titleInfo.insert(u.titleInfo.end(), dev.titleInfo.begin(), dev.titleInfo.end());
if(icons[i].getTitleID() == titleID)
return i;
}
return -1;
}
data::sortUserTitles();
return true;
}
void data::sortUserTitles()
{
for (data::user &u : data::users)
std::sort(u.titleInfo.begin(), u.titleInfo.end(), sortTitles);
}
void data::init()
{
data::loadUsersTitles(true);
}
void data::exit()
{
/*Still needed for planned future revisions*/
}
void data::setUserIndex(unsigned _sUser)
{
selUser = _sUser;
}
data::user *data::getCurrentUser()
{
return &users[selUser];
}
unsigned data::getCurrentUserIndex()
{
return selUser;
}
void data::setTitleIndex(unsigned _sTitle)
{
selData = _sTitle;
}
data::userTitleInfo *data::getCurrentUserTitleInfo()
{
return &users[selUser].titleInfo[selData];
}
unsigned data::getCurrentUserTitleInfoIndex()
{
return selData;
}
data::titleInfo *data::getTitleInfoByTID(const uint64_t &tid)
{
if (titles.find(tid) != titles.end())
return &titles[tid];
return NULL;
}
std::string data::getTitleNameByTID(const uint64_t &tid)
{
return titles[tid].title;
}
std::string data::getTitleSafeNameByTID(const uint64_t &tid)
{
return titles[tid].safeTitle;
}
SDL_Texture *data::getTitleIconByTID(const uint64_t &tid)
{
return titles[tid].icon;
}
int data::getTitleIndexInUser(const data::user &u, const uint64_t &tid)
{
for (unsigned i = 0; i < u.titleInfo.size(); i++)
bool titledata::init(const FsSaveDataInfo& inf)
{
if (u.titleInfo[i].tid == tid)
return i;
}
return -1;
}
Result res = 0;
NsApplicationControlData *dat = new NsApplicationControlData;
std::memset(dat, 0, sizeof(NsApplicationControlData));
NacpLanguageEntry *ent = NULL;
data::user::user(AccountUid _id, const std::string &_backupName, const std::string &_safeBackupName)
{
userID = _id;
uID128 = util::accountUIDToU128(_id);
if(inf.SaveDataType == FsSaveDataType_SaveData)
id = inf.titleID;
else if(inf.SaveDataType == FsSaveDataType_SystemSaveData)
id = inf.saveID;
AccountProfile prof;
AccountProfileBase base;
uID = inf.userID;
type = (FsSaveDataType)inf.SaveDataType;
size_t outSz = 0;
if (R_SUCCEEDED(accountGetProfile(&prof, userID)) && R_SUCCEEDED(accountProfileGet(&prof, NULL, &base)))
{
username = base.nickname;
userSafe = util::safeString(username);
if (userSafe.empty())
res = nsGetApplicationControlData(1, id, dat, sizeof(NsApplicationControlData), &outSz);
if(R_FAILED(res) || outSz < sizeof(dat->nacp))
{
if(!sysSave)
printf("nsGetAppCtrlData Failed: 0x%08X\n", (unsigned)res);
delete dat;
}
if(R_SUCCEEDED(res))
{
res = nacpGetLanguageEntry(&dat->nacp, &ent);
if(R_FAILED(res) || ent == NULL)
{
printf("nacpGetLanguageEntry Failed\n");
delete dat;
}
}
if(R_SUCCEEDED(res))
{
title.assign(ent->name);
titleSafe = util::safeString(ent->name);
int iconIndex = findIcnIndex(id);
if(iconIndex == -1)
{
uint32_t icnSize = outSz - sizeof(dat->nacp);
icn newIcon;
newIcon.load(id, dat->icon, icnSize);
icons.push_back(newIcon);
icon = icons[findIcnIndex(id)];
}
else
icon = icons[iconIndex];
delete dat;
}
else
{
char tmp[32];
sprintf(tmp, "Acc%08X", (uint32_t)uID128);
userSafe = tmp;
sprintf(tmp, "%016lX", (u64)id);
title.assign(tmp);
titleSafe = util::safeString(tmp);
icon = icons[0];
}
uint32_t jpgSize = 0;
accountProfileGetImageSize(&prof, &jpgSize);
uint8_t *jpegData = new uint8_t[jpgSize];
accountProfileLoadImage(&prof, jpegData, jpgSize, &jpgSize);
userIcon = gfx::texMgr->textureLoadFromMem(IMG_FMT_JPG, jpegData, jpgSize);
delete[] jpegData;
return true;
}
bool titledata::isMountable(const u128& uID)
{
data::user tmpUser;
tmpUser.initNoChk(uID);
if(fs::mountSave(tmpUser, *this))
{
fsdevUnmountDevice("sv");
return true;
}
return false;
}
bool user::init(const u128& _id)
{
Result res = 0;
userID = _id;
AccountProfile prof;
AccountProfileBase base;
res = accountGetProfile(&prof, userID);
if(R_FAILED(res))
return false;
res = accountProfileGet(&prof, NULL, &base);
if(R_FAILED(res))
return false;
username.assign(base.username);
if(username.empty())
username = "Unknown";
userSafe = util::safeString(username);
size_t sz = 0;
accountProfileGetImageSize(&prof, &sz);
uint8_t *profJpeg = new uint8_t[sz];
accountProfileLoadImage(&prof, profJpeg, sz, &sz);
userIcon = texLoadJPEGMem(profJpeg, sz);
delete[] profJpeg;
accountProfileClose(&prof);
return true;
}
else
bool user::initNoChk(const u128& _id)
{
username = _backupName.empty() ? util::getIDStr((uint64_t)uID128) : _backupName;
userSafe = _safeBackupName.empty() ? util::getIDStr((uint64_t)uID128) : _safeBackupName;
userIcon = util::createIconGeneric(_backupName.c_str(), 48, false);
Result res = 0;
userID = _id;
AccountProfile prof;
AccountProfileBase base;
res = accountGetProfile(&prof, userID);
if(R_SUCCEEDED(res))
{
res = accountProfileGet(&prof, NULL, &base);
}
if(R_SUCCEEDED(res))
{
username.assign(base.username);
userSafe = util::safeString(username);
accountProfileClose(&prof);
}
else
{
username = "Unknown";
userSafe = "Unknown";
//This shouldn't happen too much
userIcon = texLoadPNGFile("romfs:/img/icn/icnDefault.png");
}
return true;
}
titles.reserve(64);
}
data::user::user(AccountUid _id, const std::string &_backupName, const std::string &_safeBackupName, SDL_Texture *img)
: user(_id, _backupName, _safeBackupName)
{
delIcon();
userIcon = img;
titles.reserve(64);
}
void data::user::setUID(AccountUid _id)
{
userID = _id;
uID128 = util::accountUIDToU128(_id);
}
void data::user::addUserTitleInfo(const uint64_t &tid, const FsSaveDataInfo *_saveInfo, const PdmPlayStatistics *_stats)
{
data::userTitleInfo newInfo;
newInfo.tid = tid;
memcpy(&newInfo.saveInfo, _saveInfo, sizeof(FsSaveDataInfo));
memcpy(&newInfo.playStats, _stats, sizeof(PdmPlayStatistics));
titleInfo.push_back(newInfo);
}
static constexpr SDL_Color green = {0x00, 0xDD, 0x00, 0xFF};
void data::dispStats()
{
data::user *cu = data::getCurrentUser();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
//Easiest/laziest way to do this
std::string stats = ui::getUICString("debugStatus", 0) + std::to_string(users.size()) + "\n";
for (data::user &u : data::users)
stats += u.getUsername() + ": " + std::to_string(u.titleInfo.size()) + "\n";
stats += ui::getUICString("debugStatus", 1) + cu->getUsername() + "\n";
stats += ui::getUICString("debugStatus", 2) + data::getTitleNameByTID(d->tid) + "\n";
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());
}

326
src/file.cpp Normal file
View File

@ -0,0 +1,326 @@
#include <fstream>
#include <cstdio>
#include <switch.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>
#include "file.h"
#include "util.h"
#include "ui.h"
#include "gfx.h"
#include "data.h"
#define BUFF_SIZE 512 * 1024
static std::string wd;
namespace fs
{
void init()
{
mkdir("sdmc:/JKSV", 777);
chdir("sdmc:/JKSV");
wd = "sdmc:/JKSV/";
}
bool mountSave(data::user& usr, data::titledata& open)
{
FsFileSystem sv;
Result res = 0;
if(open.getType() == FsSaveDataType_SaveData)
{
res = fsMount_SaveData(&sv, open.getID(), usr.getUID());
if(R_FAILED(res))
return false;
int r = fsdevMountDevice("sv", sv);
if(r == -1)
return false;
}
else if(data::sysSave)
{
res = fsMount_SystemSaveData(&sv, open.getID());
if(R_FAILED(res))
return false;
int r = fsdevMountDevice("sv", sv);
if(r == -1)
return false;
}
return true;
}
dirList::dirList(const std::string& _path)
{
path = _path;
d = opendir(path.c_str());
while((ent = readdir(d)))
{
item.push_back(ent->d_name);
}
closedir(d);
}
void dirList::reassign(const std::string& _path)
{
path = _path;
d = opendir(path.c_str());
item.clear();
while((ent = readdir(d)))
{
item.push_back(ent->d_name);
}
closedir(d);
}
void dirList::rescan()
{
item.clear();
d = opendir(path.c_str());
while((ent = readdir(d)))
{
item.push_back(ent->d_name);
}
closedir(d);
}
std::string dirList::getItem(int index)
{
return item[index];
}
bool dirList::isDir(int index)
{
std::string fullPath = path + item[index];
struct stat s;
if(stat(fullPath.c_str(), &s) == 0)
{
if(S_ISDIR(s.st_mode))
return true;
}
return false;
}
unsigned dirList::getCount()
{
return item.size();
}
void copyFile(const std::string& from, const std::string& to)
{
std::fstream f(from, std::ios::in | std::ios::binary);
std::fstream t(to, std::ios::out | std::ios::binary);
f.seekg(0, f.end);
size_t fileSize = f.tellg();
f.seekg(0, f.beg);
uint8_t *buff = new uint8_t[BUFF_SIZE];
ui::progBar prog(fileSize);
std::string copyString = "Copying " + from + "...";
copyString = util::getWrappedString(copyString, 24, 1136);
for(unsigned i = 0; i < fileSize; )
{
f.read((char *)buff, BUFF_SIZE);
t.write((char *)buff, f.gcount());
i += f.gcount();
prog.update(i);
prog.draw(copyString);
gfxHandleBuffs();
}
delete[] buff;
f.close();
t.close();
}
void copyFileCommit(const std::string& from, const std::string& to, const std::string& dev)
{
std::fstream f(from, std::ios::in | std::ios::binary);
std::fstream t(to, std::ios::out | std::ios::binary);
f.seekg(0, f.end);
size_t fileSize = f.tellg();
f.seekg(0, f.beg);
uint8_t *buff = new uint8_t[BUFF_SIZE];
ui::progBar prog(fileSize);
std::string copyString = "Copying " + from + "...";
copyString = util::getWrappedString(copyString, 24, 1136);
for(unsigned i = 0; i < fileSize; )
{
f.read((char *)buff, BUFF_SIZE);
t.write((char *)buff, f.gcount());
i += f.gcount();
prog.update(i);
prog.draw(copyString);
gfxHandleBuffs();
}
delete[] buff;
f.close();
t.close();
Result res = fsdevCommitDevice(dev.c_str());
if(R_FAILED(res))
ui::showError("Error committing file to device", res);
}
void copyDirToDir(const std::string& from, const std::string& to)
{
dirList list(from);
for(unsigned i = 0; i < list.getCount(); i++)
{
if(list.isDir(i))
{
std::string newFrom = from + list.getItem(i) + "/";
std::string newTo = to + list.getItem(i);
mkdir(newTo.c_str(), 0777);
newTo += "/";
copyDirToDir(newFrom, newTo);
}
else
{
std::string fullFrom = from + list.getItem(i);
std::string fullTo = to + list.getItem(i);
copyFile(fullFrom, fullTo);
}
}
}
void copyDirToDirCommit(const std::string& from, const std::string& to, const std::string& dev)
{
dirList list(from);
for(unsigned i = 0; i < list.getCount(); i++)
{
if(list.isDir(i))
{
std::string newFrom = from + list.getItem(i) + "/";
std::string newTo = to + list.getItem(i);
mkdir(newTo.c_str(), 0777);
newTo += "/";
copyDirToDirCommit(newFrom, newTo, dev);
}
else
{
std::string fullFrom = from + list.getItem(i);
std::string fullTo = to + list.getItem(i);
copyFileCommit(fullFrom, fullTo, dev);
}
}
}
void delDir(const std::string& path)
{
dirList list(path);
for(unsigned i = 0; i < list.getCount(); i++)
{
if(list.isDir(i))
{
std::string newPath = path + "/" + list.getItem(i) + "/";
delDir(newPath);
std::string delPath = path + list.getItem(i);
rmdir(delPath.c_str());
}
else
{
std::string delPath = path + list.getItem(i);
std::remove(delPath.c_str());
}
}
rmdir(path.c_str());
}
void dumpAllUserSaves(data::user& u)
{
for(unsigned i = 0; i < u.titles.size(); i++)
{
if(fs::mountSave(u, u.titles[i]))
{
util::makeTitleDir(u, u.titles[i]);
//sdmc:/JKSV/[title]/[user] - [date]/
std::string outPath = util::getTitleDir(u, u.titles[i]) + u.getUsernameSafe() + " - " + util::getDateTime();
mkdir(outPath.c_str(), 777);
outPath += "/";
std::string root = "sv:/";
fs::copyDirToDir(root, outPath);
fsdevUnmountDevice("sv");
}
}
}
std::string getFileProps(const std::string& _path)
{
std::string ret = "";
std::fstream get(_path, std::ios::in | std::ios::binary);
if(get.is_open())
{
//Size
get.seekg(0, get.end);
unsigned fileSize = get.tellg();
get.seekg(0, get.beg);
get.close();
//Probably add more later
char tmp[256];
std::sprintf(tmp, "Path: \"%s\"\nSize: %u", _path.c_str(), fileSize);
ret = tmp;
}
return ret;
}
bool fileExists(const std::string& path)
{
std::fstream chk(path, std::ios::in);
if(chk.is_open())
{
chk.close();
return true;
}
return false;
}
std::string getWorkDir()
{
return wd;
}
}

View File

@ -1,730 +0,0 @@
#include <string>
#include <switch.h>
#include "cfg.h"
#include "fs.h"
#include "util.h"
static std::string wd = "sdmc:/JKSV/";
static FSFILE *debLog;
static FsFileSystem sv;
static std::vector<std::string> pathFilter;
void fs::init()
{
mkDirRec("sdmc:/config/JKSV/");
mkDirRec(wd);
mkdir(std::string(wd + "_TRASH_").c_str(), 777);
fs::logOpen();
}
bool fs::mountSave(const FsSaveDataInfo &_m)
{
Result svOpen;
FsSaveDataAttribute attr = {0};
switch (_m.save_data_type)
{
case FsSaveDataType_System:
case FsSaveDataType_SystemBcat:
{
attr.uid = _m.uid;
attr.system_save_data_id = _m.system_save_data_id;
attr.save_data_type = _m.save_data_type;
svOpen = fsOpenSaveDataFileSystemBySystemSaveDataId(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Account:
{
attr.uid = _m.uid;
attr.application_id = _m.application_id;
attr.save_data_type = _m.save_data_type;
attr.save_data_rank = _m.save_data_rank;
attr.save_data_index = _m.save_data_index;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Device:
{
attr.application_id = _m.application_id;
attr.save_data_type = FsSaveDataType_Device;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Bcat:
{
attr.application_id = _m.application_id;
attr.save_data_type = FsSaveDataType_Bcat;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Cache:
{
attr.application_id = _m.application_id;
attr.save_data_type = FsSaveDataType_Cache;
attr.save_data_index = _m.save_data_index;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr);
}
break;
case FsSaveDataType_Temporary:
{
attr.application_id = _m.application_id;
attr.save_data_type = _m.save_data_type;
svOpen = fsOpenSaveDataFileSystem(&sv, (FsSaveDataSpaceId)_m.save_data_space_id, &attr);
}
break;
default:
svOpen = 1;
break;
}
return R_SUCCEEDED(svOpen) && fsdevMountDevice("sv", sv) != -1;
}
bool fs::commitToDevice(const std::string &dev)
{
bool ret = true;
Result res = fsdevCommitDevice(dev.c_str());
if (R_FAILED(res))
{
fs::logWrite("Error committing file to device -> 0x%X\n", res);
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popErrorCommittingFile", 0));
ret = false;
}
return ret;
}
std::string fs::getWorkDir()
{
return wd;
}
void fs::setWorkDir(const std::string &_w)
{
wd = _w;
}
void fs::loadPathFilters(uint64_t tid)
{
char path[256];
sprintf(path, "sdmc:/config/JKSV/0x%016lX_filter.txt", tid);
if (fs::fileExists(path))
{
fs::dataFile filter(path);
while (filter.readNextLine(false))
pathFilter.push_back(filter.getLine());
}
}
bool fs::pathIsFiltered(const std::string &_path)
{
if (pathFilter.empty())
return false;
for (std::string &_p : pathFilter)
{
if (_path == _p)
return true;
}
return false;
}
void fs::freePathFilters()
{
pathFilter.clear();
}
void fs::createSaveData(FsSaveDataType _type, uint64_t _tid, AccountUid _uid, threadInfo *t)
{
data::titleInfo *tinfo = data::getTitleInfoByTID(_tid);
if (t)
t->status->setStatus(ui::getUICString("threadStatusCreatingSaveData", 0), tinfo->title.c_str());
uint16_t cacheIndex = 0;
std::string indexStr;
if (_type == FsSaveDataType_Cache &&
!(indexStr = util::getStringInput(SwkbdType_NumPad, "0", ui::getUIString("swkbdSaveIndex", 0), 2, 0, NULL))
.empty())
cacheIndex = strtoul(indexStr.c_str(), NULL, 10);
else if (_type == FsSaveDataType_Cache && indexStr.empty())
{
if (t)
t->finished = true;
return;
}
FsSaveDataAttribute attr;
memset(&attr, 0, sizeof(FsSaveDataAttribute));
attr.application_id = _tid;
attr.uid = _uid;
attr.system_save_data_id = 0;
attr.save_data_type = _type;
attr.save_data_rank = 0;
attr.save_data_index = cacheIndex;
FsSaveDataCreationInfo crt;
memset(&crt, 0, sizeof(FsSaveDataCreationInfo));
int64_t saveSize = 0, journalSize = 0;
// Grab a pointer to the nacp of the title data.
NacpStruct *nacp = &tinfo->data.nacp;
switch (_type)
{
case FsSaveDataType_Account:
{
saveSize = nacp->user_account_save_data_size;
journalSize = nacp->user_account_save_data_journal_size;
}
break;
case FsSaveDataType_Device:
{
saveSize = nacp->device_save_data_size;
journalSize = nacp->device_save_data_journal_size;
}
break;
case FsSaveDataType_Bcat:
{
saveSize = nacp->bcat_delivery_cache_storage_size;
journalSize = nacp->bcat_delivery_cache_storage_size;
}
break;
case FsSaveDataType_Cache:
{
saveSize = 32 * 1024 * 1024;
if (nacp->cache_storage_journal_size > nacp->cache_storage_data_and_journal_size_max)
{
journalSize = nacp->cache_storage_journal_size;
}
else
{
journalSize = nacp->cache_storage_data_and_journal_size_max;
}
}
break;
default:
{
if (t)
t->finished = true;
return;
}
break;
}
crt.save_data_size = saveSize;
crt.journal_size = journalSize;
crt.available_size = 0x4000;
crt.owner_id = _type == FsSaveDataType_Bcat ? 0x010000000000000C : nacp->save_data_owner_id;
crt.flags = 0;
crt.save_data_space_id = FsSaveDataSpaceId_User;
FsSaveDataMetaInfo meta;
memset(&meta, 0, sizeof(FsSaveDataMetaInfo));
if (_type != FsSaveDataType_Bcat)
{
meta.size = 0x40060;
meta.type = FsSaveDataMetaType_Thumbnail;
}
Result res = 0;
if (R_SUCCEEDED(res = fsCreateSaveDataFileSystem(&attr, &crt, &meta)))
{
util::createTitleDirectoryByTID(_tid);
data::loadUsersTitles(false);
ui::ttlRefresh();
}
else
{
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataCreationFailed", 0));
fs::logWrite("SaveCreate Failed -> %X\n", res);
}
}
static void createSaveData_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::svCreateArgs *crt = (fs::svCreateArgs *)t->argPtr;
fs::createSaveData(crt->type, crt->tid, crt->account, t);
delete crt;
t->finished = true;
}
void fs::createSaveDataThreaded(FsSaveDataType _type, uint64_t _tid, AccountUid _uid)
{
fs::svCreateArgs *send = new fs::svCreateArgs;
send->type = _type;
send->tid = _tid;
send->account = _uid;
ui::newThread(createSaveData_t, send, NULL);
}
bool fs::extendSaveData(const data::userTitleInfo *tinfo, uint64_t extSize, threadInfo *t)
{
if (t)
t->status->setStatus(ui::getUICString("threadStatusExtendingSaveData", 0),
data::getTitleNameByTID(tinfo->tid).c_str());
uint64_t journal = fs::getJournalSizeMax(tinfo);
uint64_t saveID = tinfo->saveInfo.save_data_id;
FsSaveDataSpaceId space = (FsSaveDataSpaceId)tinfo->saveInfo.save_data_space_id;
Result res = 0;
if (R_FAILED((res = fsExtendSaveDataFileSystem(space, saveID, extSize, journal))))
{
int64_t totalSize = 0;
fs::mountSave(tinfo->saveInfo);
fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &totalSize);
fs::unmountSave();
fs::logWrite("Extend Failed: %uMB to %uMB -> %X\n", totalSize / 1024 / 1024, extSize / 1024 / 1024, res);
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataExtendFailed", 0));
return false;
}
return true;
}
static void extendSaveData_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::svExtendArgs *e = (fs::svExtendArgs *)t->argPtr;
fs::extendSaveData(e->tinfo, e->extSize, t);
delete e;
t->finished = true;
}
void fs::extendSaveDataThreaded(const data::userTitleInfo *tinfo, uint64_t extSize)
{
fs::svExtendArgs *send = new fs::svExtendArgs;
send->tinfo = tinfo;
send->extSize = extSize;
ui::newThread(extendSaveData_t, send, NULL);
}
uint64_t fs::getJournalSize(const data::userTitleInfo *tinfo)
{
uint64_t ret = 0;
data::titleInfo *t = data::getTitleInfoByTID(tinfo->tid);
// NACP pointer.
NacpStruct *nacp = &t->data.nacp;
switch (tinfo->saveInfo.save_data_type)
{
case FsSaveDataType_Account:
{
ret = nacp->user_account_save_data_journal_size;
}
break;
case FsSaveDataType_Device:
{
ret = nacp->device_save_data_journal_size;
}
break;
case FsSaveDataType_Bcat:
{
ret = nacp->bcat_delivery_cache_storage_size;
}
break;
case FsSaveDataType_Cache:
{
if (nacp->cache_storage_journal_size > 0)
{
ret = nacp->cache_storage_journal_size;
}
else
{
ret = nacp->cache_storage_data_and_journal_size_max;
}
}
break;
default:
{
ret = BUFF_SIZE;
}
break;
}
return ret;
}
uint64_t fs::getJournalSizeMax(const data::userTitleInfo *tinfo)
{
uint64_t ret = 0;
data::titleInfo *extend = data::getTitleInfoByTID(tinfo->tid);
// NACP pointer
NacpStruct *nacp = &extend->data.nacp;
switch (tinfo->saveInfo.save_data_type)
{
case FsSaveDataType_Account:
{
if (nacp->user_account_save_data_journal_size_max > nacp->user_account_save_data_journal_size)
ret = nacp->user_account_save_data_journal_size_max;
else
ret = nacp->user_account_save_data_journal_size;
}
break;
case FsSaveDataType_Bcat:
{
ret = nacp->bcat_delivery_cache_storage_size;
}
break;
case FsSaveDataType_Cache:
{
if (nacp->cache_storage_data_and_journal_size_max > nacp->cache_storage_journal_size)
ret = nacp->cache_storage_data_and_journal_size_max;
else
ret = nacp->cache_storage_journal_size;
}
break;
case FsSaveDataType_Device:
{
if (nacp->device_save_data_journal_size_max > nacp->device_save_data_journal_size)
ret = nacp->device_save_data_journal_size_max;
else
ret = nacp->device_save_data_journal_size;
}
break;
default:
{
//will just fail
ret = 0;
}
break;
}
return ret;
}
static void wipeSave_t(void *a)
{
threadInfo *t = (threadInfo *)a;
t->status->setStatus(ui::getUICString("threadStatusResettingSaveData", 0));
fs::delDir("sv:/");
fs::commitToDevice("sv");
t->finished = true;
}
void fs::wipeSave()
{
ui::newThread(wipeSave_t, NULL, NULL);
}
void fs::createNewBackup(void *a)
{
if (!fs::dirNotEmpty("sv:/"))
{
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popSaveIsEmpty", 0));
return;
}
uint64_t held = ui::padKeysHeld();
data::user *u = data::getCurrentUser();
data::userTitleInfo *d = data::getCurrentUserTitleInfo();
data::titleInfo *t = data::getTitleInfoByTID(d->tid);
std::string out;
if (held & HidNpadButton_R || cfg::config["autoName"])
out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
else if (held & HidNpadButton_L)
out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YDM);
else if (held & HidNpadButton_ZL)
out = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_HOYSTE);
else
{
const std::string dict[] = {util::getDateTime(util::DATE_FMT_YMD),
util::getDateTime(util::DATE_FMT_YDM),
util::getDateTime(util::DATE_FMT_HOYSTE),
util::getDateTime(util::DATE_FMT_JHK),
util::getDateTime(util::DATE_FMT_ASC),
u->getUsernameSafe(),
t->safeTitle,
util::generateAbbrev(d->tid),
".zip"};
std::string defaultText = u->getUsernameSafe() + " - " + util::getDateTime(util::DATE_FMT_YMD);
out = util::getStringInput(SwkbdType_QWERTY, defaultText, ui::getUIString("swkbdEnterName", 0), 64, 9, dict);
out = util::safeString(out);
}
if (!out.empty())
{
std::string ext = util::getExtensionFromString(out);
std::string path = util::generatePathByTID(d->tid) + out;
if (cfg::config["zip"] || ext == "zip")
{
if (ext != "zip") //data::zip is on but extension is not zip
path += ".zip";
zipFile zip = zipOpen64(path.c_str(), 0);
fs::copyDirToZipThreaded("sv:/", zip, false, 0);
}
else
{
fs::mkDir(path);
path += "/";
fs::copyDirToDirThreaded("sv:/", path);
}
ui::fldRefreshMenu();
}
}
void fs::overwriteBackup(void *a)
{
threadInfo *t = (threadInfo *)a;
std::string *dst = (std::string *)t->argPtr;
bool saveHasFiles = fs::dirNotEmpty("sv:/");
if (fs::isDir(*dst) && saveHasFiles)
{
fs::delDir(*dst);
fs::mkDir(*dst);
dst->append("/");
fs::copyDirToDirThreaded("sv:/", *dst);
}
else if (!fs::isDir(*dst) && util::getExtensionFromString(*dst) == "zip" && saveHasFiles)
{
fs::delfile(*dst);
zipFile zip = zipOpen64(dst->c_str(), 0);
fs::copyDirToZipThreaded("sv:/", zip, false, 0);
}
delete dst;
t->finished = true;
}
void fs::restoreBackup(void *a)
{
threadInfo *t = (threadInfo *)a;
std::string *restore = (std::string *)t->argPtr;
data::user *u = data::getCurrentUser();
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
if ((utinfo->saveInfo.save_data_type != FsSaveDataType_System || cfg::config["sysSaveWrite"]))
{
bool saveHasFiles = fs::dirNotEmpty("sv:/");
if (cfg::config["autoBack"] && cfg::config["zip"] && saveHasFiles)
{
std::string autoZip = util::generatePathByTID(utinfo->tid) + "/AUTO " + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + ".zip";
zipFile zip = zipOpen64(autoZip.c_str(), 0);
fs::copyDirToZipThreaded("sv:/", zip, false, 0);
}
else if (cfg::config["autoBack"] && saveHasFiles)
{
std::string autoFolder = util::generatePathByTID(utinfo->tid) + "/AUTO - " + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + "/";
fs::mkDir(autoFolder.substr(0, autoFolder.length() - 1));
fs::copyDirToDirThreaded("sv:/", autoFolder);
}
if (fs::isDir(*restore))
{
restore->append("/");
if (fs::dirNotEmpty(*restore))
{
t->status->setStatus(ui::getUICString("threadStatusCalculatingSaveSize", 0));
unsigned dirCount = 0, fileCount = 0;
uint64_t saveSize = 0;
int64_t availSize = 0;
fs::getDirProps(*restore, dirCount, fileCount, saveSize);
fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &availSize);
if ((int)saveSize > availSize)
{
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
fs::unmountSave();
fs::extendSaveData(utinfo, saveSize + 0x500000, t);
fs::mountSave(utinfo->saveInfo);
}
fs::wipeSave();
fs::copyDirToDirCommitThreaded(*restore, "sv:/", "sv");
}
else
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popFolderIsEmpty", 0));
}
else if (!fs::isDir(*restore) && util::getExtensionFromString(*restore) == "zip")
{
unzFile unz = unzOpen64(restore->c_str());
if (unz && fs::zipNotEmpty(unz))
{
t->status->setStatus(ui::getUICString("threadStatusCalculatingSaveSize", 0));
uint64_t saveSize = fs::getZipTotalSize(unz);
int64_t availSize = 0;
fsFsGetTotalSpace(fsdevGetDeviceFileSystem("sv"), "/", &availSize);
if ((int)saveSize > availSize)
{
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
fs::unmountSave();
fs::extendSaveData(utinfo, saveSize + 0x500000, t);
fs::mountSave(utinfo->saveInfo);
}
fs::wipeSave();
fs::copyZipToDirThreaded(unz, "sv:/", "sv");
}
else
{
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popZipIsEmpty", 0));
unzClose(unz);
}
}
else
{
std::string dstPath = "sv:/" + util::getFilenameFromPath(*restore);
fs::copyFileCommitThreaded(*restore, dstPath, "sv");
}
}
if (cfg::config["autoBack"])
ui::fldRefreshMenu();
delete restore;
t->finished = true;
}
void fs::deleteBackup(void *a)
{
threadInfo *t = (threadInfo *)a;
std::string *deletePath = (std::string *)t->argPtr;
std::string backupName = util::getFilenameFromPath(*deletePath);
t->status->setStatus(ui::getUICString("threadStatusDeletingFile", 0));
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
if (cfg::config["trashBin"])
{
std::string oldPath = *deletePath;
std::string trashPath = wd + "_TRASH_/" + data::getTitleSafeNameByTID(utinfo->tid);
fs::mkDir(trashPath);
trashPath += "/" + backupName;
rename(oldPath.c_str(), trashPath.c_str());
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupMovedToTrash", 0), backupName.c_str());
}
else if (fs::isDir(*deletePath))
{
*deletePath += "/";
fs::delDir(*deletePath);
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str());
}
else
{
fs::delfile(*deletePath);
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("saveDataBackupDeleted", 0), backupName.c_str());
}
ui::fldRefreshMenu();
delete deletePath;
t->finished = true;
}
void fs::dumpAllUserSaves(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *c = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
t->argPtr = c;
data::user *u = data::getCurrentUser();
for (unsigned i = 0; i < u->titleInfo.size(); i++)
{
bool saveMounted = fs::mountSave(u->titleInfo[i].saveInfo);
util::createTitleDirectoryByTID(u->titleInfo[i].tid);
if (saveMounted && fs::dirNotEmpty("sv:/") && cfg::config["zip"])
{
fs::loadPathFilters(u->titleInfo[i].tid);
std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + ".zip";
zipFile zip = zipOpen64(dst.c_str(), 0);
fs::copyDirToZip("sv:/", zip, false, 0, t);
zipClose(zip, NULL);
fs::freePathFilters();
}
else if (saveMounted && fs::dirNotEmpty("sv:/"))
{
fs::loadPathFilters(u->titleInfo[i].tid);
std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + "/";
fs::mkDir(dst.substr(0, dst.length() - 1));
fs::copyDirToDir("sv:/", dst, t);
fs::freePathFilters();
}
fs::unmountSave();
}
fs::copyArgsDestroy(c);
t->finished = true;
}
void fs::dumpAllUsersAllSaves(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *c = fs::copyArgsCreate("", "", "", NULL, NULL, false, false, 0);
t->argPtr = c;
unsigned curUser = 0;
while (data::users[curUser].getUID128() != 2)
{
data::user *u = &data::users[curUser++];
for (unsigned i = 0; i < u->titleInfo.size(); i++)
{
bool saveMounted = fs::mountSave(u->titleInfo[i].saveInfo);
util::createTitleDirectoryByTID(u->titleInfo[i].tid);
if (saveMounted && fs::dirNotEmpty("sv:/") && cfg::config["zip"])
{
fs::loadPathFilters(u->titleInfo[i].tid);
std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + ".zip";
zipFile zip = zipOpen64(dst.c_str(), 0);
fs::copyDirToZip("sv:/", zip, false, 0, t);
zipClose(zip, NULL);
fs::freePathFilters();
}
else if (saveMounted && fs::dirNotEmpty("sv:/"))
{
fs::loadPathFilters(u->titleInfo[i].tid);
std::string dst = util::generatePathByTID(u->titleInfo[i].tid) + u->getUsernameSafe() + " - " +
util::getDateTime(util::DATE_FMT_YMD) + "/";
fs::mkDir(dst.substr(0, dst.length() - 1));
fs::copyDirToDir("sv:/", dst, t);
fs::freePathFilters();
}
fs::unmountSave();
}
}
fs::copyArgsDestroy(c);
t->finished = true;
}
void fs::logOpen()
{
std::string logPath = wd + "log.txt";
debLog = fsfopen(logPath.c_str(), FsOpenMode_Write);
fsfclose(debLog);
}
void fs::logWrite(const char *fmt, ...)
{
std::string logPath = wd + "log.txt";
debLog = fsfopen(logPath.c_str(), FsOpenMode_Append | FsOpenMode_Write);
char tmp[256];
va_list args;
va_start(args, fmt);
vsprintf(tmp, fmt, args);
va_end(args);
fsfwrite(tmp, 1, strlen(tmp), debLog);
fsfclose(debLog);
}

View File

@ -1,270 +0,0 @@
#include <switch.h>
#include <algorithm>
#include "fs.h"
#include "cfg.h"
#include "util.h"
static struct
{
bool operator()(const fs::dirItem& a, const fs::dirItem& b)
{
if(a.isDir() != b.isDir())
return a.isDir();
for(unsigned i = 0; i < a.getItm().length(); i++)
{
char charA = tolower(a.getItm()[i]);
char charB = tolower(b.getItm()[i]);
if(charA != charB)
return charA < charB;
}
return false;
}
} sortDirList;
void fs::mkDir(const std::string& _p)
{
if(cfg::config["directFsCmd"])
fsMkDir(_p.c_str());
else
mkdir(_p.c_str(), 777);
}
void fs::mkDirRec(const std::string& _p)
{
//skip first slash
size_t pos = _p.find('/', 0) + 1;
while((pos = _p.find('/', pos)) != _p.npos)
{
fs::mkDir(_p.substr(0, pos).c_str());
++pos;
}
}
void fs::delDir(const std::string& path)
{
dirList list(path);
for(unsigned i = 0; i < list.getCount(); i++)
{
if(pathIsFiltered(path + list.getItem(i)))
continue;
if(list.isDir(i))
{
std::string newPath = path + list.getItem(i) + "/";
delDir(newPath);
std::string delPath = path + list.getItem(i);
rmdir(delPath.c_str());
}
else
{
std::string delPath = path + list.getItem(i);
std::remove(delPath.c_str());
}
}
rmdir(path.c_str());
}
bool fs::dirNotEmpty(const std::string& _dir)
{
fs::dirList tmp(_dir);
return tmp.getCount() > 0;
}
bool fs::isDir(const std::string& _path)
{
struct stat s;
return stat(_path.c_str(), &s) == 0 && S_ISDIR(s.st_mode);
}
void fs::copyDirToDir(const std::string& src, const std::string& dst, threadInfo *t)
{
if(t)
t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), src.c_str());
fs::dirList *list = new fs::dirList(src);
for(unsigned i = 0; i < list->getCount(); i++)
{
if(pathIsFiltered(src + list->getItem(i)))
continue;
if(list->isDir(i))
{
std::string newSrc = src + list->getItem(i) + "/";
std::string newDst = dst + list->getItem(i) + "/";
fs::mkDir(newDst.substr(0, newDst.length() - 1));
fs::copyDirToDir(newSrc, newDst, t);
}
else
{
std::string fullSrc = src + list->getItem(i);
std::string fullDst = dst + list->getItem(i);
if(t)
t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), fullSrc.c_str());
fs::copyFile(fullSrc, fullDst, t);
}
}
delete list;
}
static void copyDirToDir_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
fs::copyDirToDir(in->src, in->dst, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyDirToDirThreaded(const std::string& src, const std::string& dst)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0);
ui::newThread(copyDirToDir_t, send, fs::fileDrawFunc);
}
void fs::copyDirToDirCommit(const std::string& src, const std::string& dst, const std::string& dev, threadInfo *t)
{
if(t)
t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), src.c_str());
fs::dirList *list = new fs::dirList(src);
for(unsigned i = 0; i < list->getCount(); i++)
{
if(pathIsFiltered(src + list->getItem(i)))
continue;
if(list->isDir(i))
{
std::string newSrc = src + list->getItem(i) + "/";
std::string newDst = dst + list->getItem(i) + "/";
fs::mkDir(newDst.substr(0, newDst.length() - 1));
fs::copyDirToDirCommit(newSrc, newDst, dev, t);
}
else
{
std::string fullSrc = src + list->getItem(i);
std::string fullDst = dst + list->getItem(i);
if(t)
t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), fullSrc.c_str());
fs::copyFileCommit(fullSrc, fullDst, dev, t);
}
}
delete list;
}
static void copyDirToDirCommit_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
fs::copyDirToDirCommit(in->src, in->dst, in->dev, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyDirToDirCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0);
ui::newThread(copyDirToDirCommit_t, send, fs::fileDrawFunc);
}
void fs::getDirProps(const std::string& path, unsigned& dirCount, unsigned& fileCount, uint64_t& totalSize)
{
fs::dirList *d = new fs::dirList(path);
for(unsigned i = 0; i < d->getCount(); i++)
{
if(d->isDir(i))
{
++dirCount;
std::string newPath = path + d->getItem(i) + "/";
fs::getDirProps(newPath, dirCount, fileCount, totalSize);
}
else
{
++fileCount;
std::string filePath = path + d->getItem(i);
totalSize += fs::fsize(filePath);
}
}
delete d;
}
fs::dirItem::dirItem(const std::string& pathTo, const std::string& sItem)
{
itm = sItem;
std::string fullPath = pathTo + sItem;
struct stat s;
if(stat(fullPath.c_str(), &s) == 0 && S_ISDIR(s.st_mode))
dir = true;
}
std::string fs::dirItem::getName() const
{
size_t extPos = itm.find_last_of('.'), slPos = itm.find_last_of('/');
if(extPos == itm.npos)
return "";
return itm.substr(slPos + 1, extPos);
}
std::string fs::dirItem::getExt() const
{
return util::getExtensionFromString(itm);
}
fs::dirList::dirList(const std::string& _path, bool ignoreDotFiles)
{
DIR *d;
struct dirent *ent;
path = _path;
d = opendir(path.c_str());
while((ent = readdir(d)))
if (!ignoreDotFiles || ent->d_name[0] != '.')
item.emplace_back(path, ent->d_name);
closedir(d);
std::sort(item.begin(), item.end(), sortDirList);
}
void fs::dirList::reassign(const std::string& _path)
{
DIR *d;
struct dirent *ent;
path = _path;
d = opendir(path.c_str());
item.clear();
while((ent = readdir(d)))
item.emplace_back(path, ent->d_name);
closedir(d);
std::sort(item.begin(), item.end(), sortDirList);
}
void fs::dirList::rescan()
{
item.clear();
DIR *d;
struct dirent *ent;
d = opendir(path.c_str());
while((ent = readdir(d)))
item.emplace_back(path, ent->d_name);
closedir(d);
std::sort(item.begin(), item.end(), sortDirList);
}

View File

@ -1,395 +0,0 @@
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <vector>
#include <switch.h>
#include <unistd.h>
#include <cstdarg>
#include <mutex>
#include <condition_variable>
#include <sys/stat.h>
#include "fs.h"
#include "util.h"
#include "ui.h"
#include "gfx.h"
#include "data.h"
#include "cfg.h"
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;
ret->src = src;
ret->dst = dst;
ret->dev = dev;
ret->z = z;
ret->unz = unz;
ret->cleanup = _cleanup;
ret->prog = new ui::progBar;
ret->prog->setMax(0);
ret->prog->update(0);
ret->offset = 0;
ret->trimZipPath = _trimZipPath;
ret->trimZipPlaces = _trimPlaces;
return ret;
}
void fs::copyArgsDestroy(copyArgs *c)
{
delete c->prog;
delete c;
c = NULL;
}
fs::dataFile::dataFile(const std::string& _path)
{
f = fopen(_path.c_str(), "r");
if(f != NULL)
opened = true;
}
fs::dataFile::~dataFile()
{
fclose(f);
}
bool fs::dataFile::readNextLine(bool proc)
{
bool ret = false;
char tmp[1024];
while(fgets(tmp, 1024, f))
{
if(tmp[0] != '#' && tmp[0] != '\n' && tmp[0] != '\r')
{
line = tmp;
ret = true;
break;
}
}
util::stripChar('\n', line);
util::stripChar('\r', line);
if(proc)
procLine();
return ret;
}
void fs::dataFile::procLine()
{
size_t pPos = line.find_first_of("(=,");
if(pPos != line.npos)
{
lPos = pPos;
name.assign(line.begin(), line.begin() + lPos);
}
else
name = line;
util::stripChar(' ', name);
++lPos;
}
std::string fs::dataFile::getNextValueStr()
{
std::string ret = "";
//Skip all spaces until we hit actual text
size_t pos1 = line.find_first_not_of(", ", lPos);
//If reading from quotes
if(line[pos1] == '"')
lPos = line.find_first_of('"', ++pos1);
else
lPos = line.find_first_of(",;\n", pos1);//Set lPos to end of string we want. This should just set lPos to the end of the line if it fails, which is ok
ret = line.substr(pos1, lPos++ - pos1);
util::replaceStr(ret, "\\n", "\n");
return ret;
}
int fs::dataFile::getNextValueInt()
{
int ret = 0;
std::string no = getNextValueStr();
if(no[0] == '0' && tolower(no[1]) == 'x')
ret = strtoul(no.c_str(), NULL, 16);
else
ret = strtoul(no.c_str(), NULL, 10);
return ret;
}
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(filesize);
c->prog->update(0);
}
FILE *fsrc = fopen(src.c_str(), "rb");
if(!fsrc)
{
fclose(fsrc);
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, 0x40000, 0x2E, 2);
threadStart(&writeThread);
size_t readIn = 0;
uint64_t readCount = 0;
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
readCount += readIn;
if(c)
c->offset = readCount;
if(transferBuffer.size() >= TRANSFER_BUFFER_LIMIT || readCount == filesize)
{
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)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), in->src.c_str());
fs::copyFile(in->src, in->dst, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyFileThreaded(const std::string& src, const std::string& dst)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, "", NULL, NULL, true, false, 0);
ui::newThread(copyFileThreaded_t, send, fs::fileDrawFunc);
}
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(filesize);
c->prog->update(0);
}
FILE *fsrc = fopen(src.c_str(), "rb");
if(!fsrc)
{
fclose(fsrc);
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, 0x040000, 0x2E, 2);
uint8_t *buff = new uint8_t[BUFF_SIZE];
size_t readIn = 0;
uint64_t readCount = 0;
std::vector<uint8_t> transferBuffer;
threadStart(&writeThread);
while((readIn = fread(buff, 1, BUFF_SIZE, fsrc)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
readCount += readIn;
if(c)
c->offset = readCount;
if(transferBuffer.size() >= thrdArgs.writeLimit || readCount == filesize)
{
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)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *in = (fs::copyArgs *)t->argPtr;
t->status->setStatus(ui::getUICString("threadStatusCopyingFile", 0), in->src.c_str());
in->prog->setMax(fs::fsize(in->src));
in->prog->update(0);
fs::copyFileCommit(in->src, in->dst, in->dev, t);
if(in->cleanup)
fs::copyArgsDestroy(in);
t->finished = true;
}
void fs::copyFileCommitThreaded(const std::string& src, const std::string& dst, const std::string& dev)
{
fs::copyArgs *send = fs::copyArgsCreate(src, dst, dev, NULL, NULL, true, false, 0);
ui::newThread(copyFileCommit_t, send, fs::fileDrawFunc);
}
void fs::fileDrawFunc(void *a)
{
threadInfo *t = (threadInfo *)a;
if(!t->finished && t->argPtr)
{
copyArgs *c = (copyArgs *)t->argPtr;
std::string tmp;
t->status->getStatus(tmp);
c->argLock();
c->prog->update(c->offset);
c->prog->draw(tmp);
c->argUnlock();
}
}
void fs::delfile(const std::string& path)
{
if(cfg::config["directFsCmd"])
fsremove(path.c_str());
else
remove(path.c_str());
}
void fs::getShowFileProps(const std::string& _path)
{
size_t size = fs::fsize(_path);
ui::showMessage(ui::getUICString("fileModeFileProperties", 0), _path.c_str(), util::getSizeString(size).c_str());
}
bool fs::fileExists(const std::string& path)
{
bool ret = false;
FILE *test = fopen(path.c_str(), "rb");
if(test != NULL)
ret = true;
fclose(test);
return ret;
}
size_t fs::fsize(const std::string& _f)
{
size_t ret = 0;
FILE *get = fopen(_f.c_str(), "rb");
if(get != NULL)
{
fseek(get, 0, SEEK_END);
ret = ftell(get);
}
fclose(get);
return ret;
}

View File

@ -1,150 +0,0 @@
#include <switch.h>
#include <string.h>
#include <stdint.h>
#include <malloc.h>
#include "fs/fsfile.h"
char *getDeviceFromPath(char *dev, size_t _max, const char *path)
{
memset(dev, 0, _max);
char *c = strchr(path, ':');
if(c - path > _max)
return NULL;
//probably not good? idk
memcpy(dev, path, c - path);
return dev;
}
char *getFilePath(char *pathOut, size_t _max, const char *path)
{
memset(pathOut, 0, _max);
char *c = strchr(path, '/');
size_t pLength = strlen(c);
if(pLength > _max)
return NULL;
memcpy(pathOut, c, pLength);
return pathOut;
}
bool fsMkDir(const char *_p)
{
char devStr[16];
char path[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p))
return false;
Result res = fsFsCreateDirectory(fsdevGetDeviceFileSystem(devStr), path);
return res == 0;
}
int fsremove(const char *_p)
{
char devStr[16];
char path[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(path, FS_MAX_PATH, _p))
return -1;
Result res = fsFsDeleteFile(fsdevGetDeviceFileSystem(devStr), path);
return res;
}
Result fsDelDirRec(const char *_p)
{
char devStr[16];
char path[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || ! getFilePath(path, FS_MAX_PATH, _p))
return 1;
return fsFsDeleteDirectoryRecursively(fsdevGetDeviceFileSystem(devStr), path);
}
bool fsfcreate(const char *_p, int64_t crSize)
{
char devStr[16];
char filePath[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p))
return false;
FsFileSystem *s = fsdevGetDeviceFileSystem(devStr);
if(s == NULL)
return false;
Result res = fsFsCreateFile(s, filePath, crSize, 0);
if(R_SUCCEEDED(res))
res = fsdevCommitDevice(devStr);
return R_SUCCEEDED(res) ? true : false;
}
FSFILE *fsfopen(const char *_p, uint32_t mode)
{
char devStr[16];
char filePath[FS_MAX_PATH];
if(!getDeviceFromPath(devStr, 16, _p) || !getFilePath(filePath, FS_MAX_PATH, _p))
return NULL;
FsFileSystem *s = fsdevGetDeviceFileSystem(devStr);
if(s == NULL)
return NULL;
if(mode == FsOpenMode_Write)
{
fsFsDeleteFile(s, filePath);
fsFsCreateFile(s, filePath, 0, 0);
}
FSFILE *ret = malloc(sizeof(FSFILE));
ret->error = fsFsOpenFile(s, filePath, mode, &ret->_f);
if(R_FAILED(ret->error))
{
free(ret);
return NULL;
}
fsFileGetSize(&ret->_f, &ret->fsize);
ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0;
return ret;
}
FSFILE *fsfopenWithSystem(FsFileSystem *_s, const char *_p, uint32_t mode)
{
if(mode & FsOpenMode_Write)
{
fsFsDeleteFile(_s, _p);
fsFsCreateFile(_s, _p, 0, 0);
}
else if(mode & FsOpenMode_Append)
fsFsCreateFile(_s, _p, 0, 0);
FSFILE *ret = malloc(sizeof(FSFILE));
ret->error = fsFsOpenFile(_s, _p, mode, &ret->_f);
if(R_FAILED(ret->error))
{
free(ret);
return NULL;
}
fsFileGetSize(&ret->_f, &ret->fsize);
ret->offset = (mode & FsOpenMode_Append) ? ret->fsize : 0;
return ret;
}
size_t fsfwrite(const void *buf, size_t sz, size_t count, FSFILE *_f)
{
size_t fullSize = sz * count;
if(_f->offset + fullSize > _f->fsize)
{
s64 newSize = (_f->fsize + fullSize) - (_f->fsize - _f->offset);
fsFileSetSize(&_f->_f, newSize);
_f->fsize = newSize;
}
_f->error = fsFileWrite(&_f->_f, _f->offset, buf, fullSize, FsWriteOption_Flush);
_f->offset += fullSize;
return fullSize;
}

View File

@ -1,134 +0,0 @@
#include "fs.h"
#include "rfs.h"
#include "gd.h"
#include "webdav.h"
#include "cfg.h"
#include "ui.h"
rfs::IRemoteFS *fs::rfs = NULL;
std::string fs::rfsRootID;
void fs::remoteInit()
{
// Google Drive has priority
driveInit();
webDavInit();
}
void fs::remoteExit()
{
if(rfs) {
delete rfs;
rfs = NULL;
}
}
void fs::driveInit()
{
// Already initialized?
if (rfs)
return;
if(cfg::driveClientID.empty() || cfg::driveClientSecret.empty())
return;
bool refreshed = false, exchanged = false;
drive::gd *gDrive = new drive::gd;
gDrive->setClientID(cfg::driveClientID);
gDrive->setClientSecret(cfg::driveClientSecret);
if(!cfg::driveRefreshToken.empty())
{
gDrive->setRefreshToken(cfg::driveRefreshToken);
refreshed = gDrive->refreshToken();
}
if(!refreshed)
{
std::string authCode = driveSignInGetAuthCode();
exchanged = gDrive->exhangeAuthCode(authCode);
}
if(gDrive->hasToken())
{
if(exchanged)
{
cfg::driveRefreshToken = gDrive->getRefreshToken();
cfg::saveConfig();
}
gDrive->driveListInit("");
if(!gDrive->dirExists(JKSV_DRIVE_FOLDER))
gDrive->createDir(JKSV_DRIVE_FOLDER, "");
rfsRootID = gDrive->getDirID(JKSV_DRIVE_FOLDER);
rfs = gDrive;
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveStarted", 0));
}
else
{
delete gDrive;
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popDriveFailed", 0));
}
}
std::string fs::driveSignInGetAuthCode()
{
std::string url = "https://accounts.google.com/o/oauth2/v2/auth?client_id=" + cfg::driveClientID + "&redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto&response_type=code&scope=https://www.googleapis.com/auth/drive";
std::string replyURL;
WebCommonConfig webCfg;
WebCommonReply webReply;
webPageCreate(&webCfg, url.c_str());
webConfigSetCallbackUrl(&webCfg, "https://accounts.google.com/o/oauth2/approval/");
webConfigShow(&webCfg, &webReply);
size_t rLength = 0;
char replyURLCstr[0x1000];
webReplyGetLastUrl(&webReply, replyURLCstr, 0x1000, &rLength);
//Prevent crash if empty.
if(strlen(replyURLCstr) == 0)
return "";
replyURL.assign(replyURLCstr);
int unescLength = 0;
size_t codeBegin = replyURL.find("approvalCode") + 13, codeEnd = replyURL.find_last_of('#');
size_t codeLength = codeEnd - codeBegin;
replyURL = replyURL.substr(codeBegin, codeLength);
char *urlUnesc = curl_easy_unescape(NULL, replyURL.c_str(), replyURL.length(), &unescLength);
replyURL = urlUnesc;
curl_free(urlUnesc);
//Finally
return replyURL;
}
void fs::webDavInit() {
// Already initialized?
if (rfs)
return;
if (cfg::webdavOrigin.empty())
return;
rfs::WebDav *webdav = new rfs::WebDav(cfg::webdavOrigin,
cfg::webdavUser,
cfg::webdavPassword);
std::string baseId = "/" + cfg::webdavBasePath + (cfg::webdavBasePath.empty() ? "" : "/");
rfsRootID = webdav->getDirID(JKSV_DRIVE_FOLDER, baseId);
// check access
if (!webdav->dirExists(JKSV_DRIVE_FOLDER, baseId)) // this could return false on auth/config related errors
{
if (!webdav->createDir(JKSV_DRIVE_FOLDER, baseId))
{
delete webdav;
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popWebdavFailed", 0));
return;
}
}
rfs = webdav;
ui::showPopMessage(POP_FRAME_DEFAULT, ui::getUICString("popWebdavStarted", 0));
}

View File

@ -1,256 +0,0 @@
#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;
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)
{
fs::copyArgs *c = NULL;
if(t)
{
t->status->setStatus(ui::getUICString("threadStatusOpeningFolder", 0), src.c_str());
c = (fs::copyArgs *)t->argPtr;
}
fs::dirList *list = new fs::dirList(src);
for(unsigned i = 0; i < list->getCount(); i++)
{
std::string itm = list->getItem(i);
if(fs::pathIsFiltered(src + itm))
continue;
if(list->isDir(i))
{
std::string newSrc = src + itm + "/";
fs::copyDirToZip(newSrc, dst, trimPath, trimPlaces, t);
}
else
{
time_t raw;
time(&raw);
tm *locTime = localtime(&raw);
zip_fileinfo inf = { locTime->tm_sec, locTime->tm_min, locTime->tm_hour,
locTime->tm_mday, locTime->tm_mon, (1900 + locTime->tm_year), 0, 0, 0 };
std::string filename = src + itm;
size_t zipNameStart = 0;
if(trimPath)
util::trimPath(filename, trimPlaces);
else
zipNameStart = filename.find_first_of('/') + 1;
if(t)
t->status->setStatus(ui::getUICString("threadStatusAddingFileToZip", 0), itm.c_str());
int zipOpenFile = zipOpenNewFileInZip64(dst, filename.substr(zipNameStart, filename.npos).c_str(), &inf, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0);
if(zipOpenFile == ZIP_OK)
{
std::string fullSrc = src + itm;
if(c)
{
c->offset = 0;
c->prog->setMax(fs::fsize(fullSrc));
c->prog->update(0);
}
FILE *fsrc = fopen(fullSrc.c_str(), "rb");
size_t readIn = 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)
c->offset += readIn;
}
delete[] buff;
fclose(fsrc);
}
}
}
}
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);
delete c;
}
t->finished = true;
}
void fs::copyDirToZipThreaded(const std::string& src, zipFile dst, bool trimPath, int trimPlaces)
{
fs::copyArgs *send = fs::copyArgsCreate(src, "", "", dst, NULL, true, false, 0);
ui::newThread(copyDirToZip_t, send, fs::fileDrawFunc);
}
void fs::copyZipToDir(unzFile src, const std::string& dst, const std::string& dev, threadInfo *t)
{
fs::copyArgs *c = NULL;
if(t)
c = (fs::copyArgs *)t->argPtr;
data::userTitleInfo *utinfo = data::getCurrentUserTitleInfo();
uint64_t journalSize = getJournalSize(utinfo);
char filename[FS_MAX_PATH];
uint8_t *buff = new uint8_t[BUFF_SIZE];
int readIn = 0;
unz_file_info64 info;
do
{
unzGetCurrentFileInfo64(src, &info, filename, FS_MAX_PATH, NULL, 0, NULL, 0);
if(unzOpenCurrentFile(src) == UNZ_OK)
{
if(t)
t->status->setStatus(ui::getUICString("threadStatusDecompressingFile", 0), filename);
if(c)
{
c->prog->setMax(info.uncompressed_size);
c->prog->update(0);
c->offset = 0;
}
std::string fullDst = dst + filename;
fs::mkDirRec(fullDst.substr(0, fullDst.find_last_of('/') + 1));
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;
uint64_t readCount = 0;
while((readIn = unzReadCurrentFile(src, buff, BUFF_SIZE)) > 0)
{
transferBuffer.insert(transferBuffer.end(), buff, buff + readIn);
readCount += readIn;
if(c)
c->offset += readIn;
if(transferBuffer.size() >= unzThrd.writeLimit || readCount == info.uncompressed_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();
}
}
threadWaitForExit(&writeThread);
threadClose(&writeThread);
fs::commitToDevice(dev);
}
}
while(unzGoToNextFile(src) != UNZ_END_OF_LIST_OF_FILE);
delete[] buff;
}
static void copyZipToDir_t(void *a)
{
threadInfo *t = (threadInfo *)a;
fs::copyArgs *c = (fs::copyArgs *)t->argPtr;
fs::copyZipToDir(c->unz, c->dst, c->dev, t);
if(c->cleanup)
{
unzClose(c->unz);
delete c;
}
t->finished = true;
}
void fs::copyZipToDirThreaded(unzFile src, const std::string& dst, const std::string& dev)
{
fs::copyArgs *send = fs::copyArgsCreate("", dst, dev, NULL, src, true, false, 0);
ui::newThread(copyZipToDir_t, send, fs::fileDrawFunc);
}
uint64_t fs::getZipTotalSize(unzFile unz)
{
uint64_t ret = 0;
if(unzGoToFirstFile(unz) == UNZ_OK)
{
unz_file_info64 finfo;
char filename[FS_MAX_PATH];
do
{
unzGetCurrentFileInfo64(unz, &finfo, filename, FS_MAX_PATH, NULL, 0, NULL, 0);
ret += finfo.uncompressed_size;
} while(unzGoToNextFile(unz) != UNZ_END_OF_LIST_OF_FILE);
unzGoToFirstFile(unz);
}
return ret;
}
bool fs::zipNotEmpty(unzFile unz)
{
return unzGoToFirstFile(unz) == UNZ_OK;
}

View File

@ -1,646 +0,0 @@
#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_DEFAULT_PARAMS_AND_QUERY "?fields=files(name,id,mimeType,size,parents)&pageSize=1000&q=trashed=false\%20and\%20\%27me\%27\%20in\%20owners"
#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"
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);
}
bool 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:auto");
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, USER_AGENT);
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", jsonResp->c_str());
}
else
writeCurlError("exchangeAuthCode", error);
delete jsonResp;
json_object_put(post);
json_object_put(respParse);
curl_slist_free_all(postHeader);
curl_easy_cleanup(curl);
return true;
}
bool drive::gd::refreshToken()
{
bool ret = false;
// 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, USER_AGENT);
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, *error;
json_object_object_get_ex(parse, "access_token", &accessToken);
json_object_object_get_ex(parse, "error", &error);
if(accessToken)
{
token = json_object_get_string(accessToken);
ret = true;
}
else if(error)
writeDriveError("refreshToken", jsonResp->c_str());
}
delete jsonResp;
json_object_put(post);
json_object_put(parse);
curl_slist_free_all(header);
curl_easy_cleanup(curl);
return ret;
}
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, USER_AGENT);
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;
}
static int requestList(const std::string& _url, const std::string& _token, std::string *_respOut)
{
int ret = 0;
// Headers needed
curl_slist *postHeaders = NULL;
postHeaders = curl_slist_append(postHeaders, std::string(HEADER_AUTHORIZATION + _token).c_str());
CURL *curl = curl_easy_init();
curl_easy_setopt(curl, CURLOPT_HTTPGET, 1);
curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, "");
curl_easy_setopt(curl, CURLOPT_USERAGENT, USER_AGENT);
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, _respOut);
ret = curl_easy_perform(curl);
curl_slist_free_all(postHeaders);
curl_easy_cleanup(curl);
return ret;
}
static void processList(const std::string& _json, std::vector<rfs::RfsItem>& _drvl, bool _clear)
{
if(_clear)
_drvl.clear();
json_object *parse = json_tokener_parse(_json.c_str()), *fileArray;
json_object_object_get_ex(parse, "files", &fileArray);
if(fileArray)
{
size_t arrayLength = json_object_array_length(fileArray);
_drvl.reserve(_drvl.size() + arrayLength);
for(unsigned i = 0; i < arrayLength; 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);
rfs::RfsItem newDirItem;
newDirItem.name = json_object_get_string(nameString);
newDirItem.id = json_object_get_string(idString);
newDirItem.size = json_object_get_int(size);
if(strcmp(json_object_get_string(mimeTypeString), MIMETYPE_FOLDER) == 0)
newDirItem.isDir = true;
if (parentArray)
{
size_t parentCount = json_object_array_length(parentArray);
//There can only be 1 parent, but it's held in an array...
for (unsigned j = 0; j < parentCount; j++)
{
json_object *parent = json_object_array_get_idx(parentArray, j);
newDirItem.parent = json_object_get_string(parent);
}
}
_drvl.push_back(newDirItem);
}
}
json_object_put(parse);
}
void drive::gd::driveListInit(const std::string& _q)
{
if(!tokenIsValid())
refreshToken();
// Request url with specific fields needed.
std::string url = std::string(driveURL) + std::string(DRIVE_DEFAULT_PARAMS_AND_QUERY);
if(!_q.empty())
{
char *qEsc = curl_easy_escape(NULL, _q.c_str(), _q.length());
url.append(std::string("\%20and\%20") + std::string(qEsc));
curl_free(qEsc);
}
std::string jsonResp;
int error = requestList(url, token, &jsonResp);
if(error == CURLE_OK)
processList(jsonResp, driveList, true);
else
writeCurlError("driveListInit", error);
}
void drive::gd::driveListAppend(const std::string& _q)
{
if(!tokenIsValid())
refreshToken();
std::string url = std::string(driveURL) + std::string(DRIVE_DEFAULT_PARAMS_AND_QUERY);
if(!_q.empty())
{
char *qEsc = curl_easy_escape(NULL, _q.c_str(), _q.length());
url.append(std::string("\%20and\%20") + std::string(qEsc));
curl_free(qEsc);
}
std::string jsonResp;
int error = requestList(url, token, &jsonResp);
if(error == CURLE_OK)
processList(jsonResp, driveList, false);
else
writeCurlError("driveListAppend", error);
}
std::vector<rfs::RfsItem> drive::gd::getListWithParent(const std::string& _parent) {
std::vector<rfs::RfsItem> filtered;
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].parent == _parent)
filtered.push_back(driveList[i]);
}
return filtered;
}
void drive::gd::debugWriteList()
{
for(auto& di : driveList)
{
fs::logWrite("%s\n\t%s\n", di.name.c_str(), di.id.c_str());
if(!di.parent.empty())
fs::logWrite("\t%s\n", di.parent.c_str());
}
}
bool drive::gd::createDir(const std::string& _dirName, const std::string& _parent)
{
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 (!_parent.empty())
{
json_object *parentsArray = json_object_new_array();
json_object *parentString = json_object_new_string(_parent.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, USER_AGENT);
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);
rfs::RfsItem newDir;
newDir.name = _dirName;
newDir.id = json_object_get_string(id);
newDir.isDir = true;
newDir.size = 0;
newDir.parent = _parent;
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)
{
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].isDir && driveList[i].name == _dirName)
return true;
}
return false;
}
bool drive::gd::dirExists(const std::string& _dirName, const std::string& _parent)
{
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].isDir && driveList[i].name == _dirName && driveList[i].parent == _parent)
return true;
}
return false;
}
bool drive::gd::fileExists(const std::string& _filename, const std::string& _parent)
{
for(unsigned i = 0; i < driveList.size(); i++)
{
if(!driveList[i].isDir && driveList[i].name == _filename && driveList[i].parent == _parent)
return true;
}
return false;
}
void drive::gd::uploadFile(const std::string& _filename, const std::string& _parent, 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 (!_parent.empty())
{
json_object *parentArray = json_object_new_array();
json_object *parentString = json_object_new_string(_parent.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, USER_AGENT);
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, 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)
{
rfs::RfsItem uploadData;
uploadData.id = json_object_get_string(id);
uploadData.name = json_object_get_string(name);
uploadData.isDir = false;
uploadData.size = *_upload->o;//should be safe to use
uploadData.parent = _parent;
driveList.push_back(uploadData);
}
json_object_put(parse);
}
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, USER_AGENT);
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, UPLOAD_BUFFER_SIZE);
curl_easy_setopt(curlPatch, CURLOPT_UPLOAD, 1);
curl_easy_perform(curlPatch);
curl_easy_cleanup(curlPatch);
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].id == _fileID)
{
driveList[i].size = *_upload->o;
break;
}
}
}
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
rfs::dlWriteThreadStruct dlWrite;
dlWrite.cfa = _download;
Thread writeThread;
threadCreate(&writeThread, rfs::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, USER_AGENT);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, getHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, rfs::writeDataBufferThreaded);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &dlWrite);
threadStart(&writeThread);
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, USER_AGENT);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, delHeaders);
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_perform(curl);
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].id == _fileID)
{
driveList.erase(driveList.begin() + i);
break;
}
}
curl_slist_free_all(delHeaders);
curl_easy_cleanup(curl);
}
std::string drive::gd::getFileID(const std::string& _name, const std::string& _parent)
{
for(unsigned i = 0; i < driveList.size(); i++)
{
if(!driveList[i].isDir && driveList[i].name == _name && driveList[i].parent == _parent)
return driveList[i].id;
}
return "";
}
std::string drive::gd::getDirID(const std::string& _name)
{
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].isDir && driveList[i].name == _name)
return driveList[i].id;
}
return "";
}
std::string drive::gd::getDirID(const std::string& _name, const std::string& _parent)
{
for(unsigned i = 0; i < driveList.size(); i++)
{
if(driveList[i].isDir && driveList[i].name == _name && driveList[i].parent == _parent)
return driveList[i].id;
}
return "";
}

569
src/gfx.c Normal file
View File

@ -0,0 +1,569 @@
#include <switch.h>
#include <stdio.h>
#include <string.h>
#include <malloc.h>
#include <png.h>
#include <jpeglib.h>
#include "gfx.h"
static uint32_t fbw = 0, fbh = 0;
static tex *frameBuffer;
static inline uint32_t blend(const color px, const color fb)
{
if(px.a == 0x00)
return colorGetColor(fb);
else if(px.a == 0xFF)
return colorGetColor(px);
uint8_t subAl = 0xFF - px.a;
uint8_t fR = (px.r * px.a + fb.r * subAl) / 0xFF;
uint8_t fG = (px.g * px.a + fb.g * subAl) / 0xFF;
uint8_t fB = (px.b * px.a + fb.b * subAl) / 0xFF;
return (0xFF << 24 | fB << 16 | fG << 8 | fR);
}
static inline uint32_t smooth(const color px1, const color px2)
{
uint8_t fR = (px1.r + px2.r) / 2;
uint8_t fG = (px1.g + px2.g) / 2;
uint8_t fB = (px1.b + px2.b) / 2;
uint8_t fA = (px1.a + px2.a) / 2;
return (fA << 24 | fB << 16 | fG << 8 | fR);
}
bool graphicsInit(int windowWidth, int windowHeight)
{
gfxInitResolution((uint32_t)windowWidth, (uint32_t)windowHeight);
gfxInitDefault();
plInitialize();
consoleInit(NULL);
gfxSetMode(GfxMode_LinearDouble);
fbw = windowWidth;
fbh = windowHeight;
//Make a fake tex that points to framebuffer
frameBuffer = malloc(sizeof(tex));
frameBuffer->width = windowWidth;
frameBuffer->height = windowHeight;
frameBuffer->data = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
return true;
}
bool graphicsExit()
{
free(frameBuffer);
plExit();
gfxExit();
return true;
}
void gfxHandleBuffs()
{
gfxFlushBuffers();
gfxSwapBuffers();
gfxWaitForVsync();
}
static void drawGlyph(const FT_Bitmap *bmp, tex *target, int _x, int _y, const color c)
{
if(bmp->pixel_mode != FT_PIXEL_MODE_GRAY)
return;
uint8_t *bmpPtr = bmp->buffer;
for(int y = _y; y < _y + bmp->rows; y++)
{
uint32_t *rowPtr = &target->data[y * target->width + _x];
for(int x = _x; x < _x + bmp->width; x++, bmpPtr++, rowPtr++)
{
if(*bmpPtr > 0)
{
color txClr, tgtClr;
colorSetRGBA(&txClr, c.r, c.g, c.b, *bmpPtr);
colorCreateFromU32(&tgtClr, *rowPtr);
*rowPtr = blend(txClr, tgtClr);
}
}
}
}
void drawText(const char *str, tex *target, const font *f, int x, int y, int sz, color c)
{
int tmpX = x;
FT_Error ret = 0;
FT_GlyphSlot slot = f->face->glyph;
uint32_t tmpChr = 0;
ssize_t unitCnt = 0;
FT_Set_Char_Size(f->face, 0, sz * 64, 90, 90);
for(unsigned i = 0; i < strlen(str); )
{
unitCnt = decode_utf8(&tmpChr, (uint8_t *)&str[i]);
if(unitCnt <= 0)
break;
i += unitCnt;
if(tmpChr == '\n')
{
tmpX = x;
y += sz + 8;
continue;
}
ret = FT_Load_Glyph(f->face, FT_Get_Char_Index(f->face, tmpChr), FT_LOAD_RENDER);
if(ret)
return;
int drawY = y + (sz - slot->bitmap_top);
drawGlyph(&slot->bitmap, target, tmpX + slot->bitmap_left, drawY, c);
tmpX += slot->advance.x >> 6;
}
}
size_t textGetWidth(const char *str, const font *f, int sz)
{
size_t width = 0;
uint32_t untCnt = 0, tmpChr = 0;
FT_GlyphSlot slot = f->face->glyph;
FT_Error ret = 0;
FT_Set_Char_Size(f->face, 0, 64 * sz, 90, 90);
for(unsigned i = 0; i < strlen(str); )
{
untCnt = decode_utf8(&tmpChr, (uint8_t *)&str[i]);
if(untCnt <= 0)
break;
i += untCnt;
ret = FT_Load_Glyph(f->face, FT_Get_Char_Index(f->face, tmpChr), FT_LOAD_RENDER);
if(ret)
return 0;
width += slot->advance.x >> 6;
}
return width;
}
void clearBufferColor(const color clr)
{
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t clearClr = colorGetColor(clr);
for(unsigned i = 0; i < gfxGetFramebufferSize() / 4; i++, fb++)
*fb = clearClr;
}
void drawRect(tex *target, int x, int y, int w, int h, const color c)
{
uint32_t clr = colorGetColor(c);
for(int tY = y; tY < y + h; tY++)
{
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + w; tX++, rowPtr++)
*rowPtr = clr;
}
}
tex *texCreate(int w, int h)
{
tex *ret = malloc(sizeof(tex));
ret->width = w;
ret->height = h;
ret->data = (uint32_t *)malloc(w * h * sizeof(uint32_t));
memset(ret->data, 0, w * h * sizeof(uint32_t));
return ret;
}
tex *texLoadPNGFile(const char *path)
{
FILE *pngIn = fopen(path, "rb");
if(pngIn != NULL)
{
png_structp png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png == 0)
return NULL;
png_infop pngInfo = png_create_info_struct(png);
if(pngInfo == 0)
return NULL;
int jmp = setjmp(png_jmpbuf(png));
if(jmp)
return NULL;
png_init_io(png, pngIn);
png_read_info(png, pngInfo);
if(png_get_color_type(png, pngInfo) != PNG_COLOR_TYPE_RGBA)
{
png_destroy_read_struct(&png, &pngInfo, NULL);
return NULL;
}
tex *ret = malloc(sizeof(tex));
ret->width = png_get_image_width(png, pngInfo);
ret->height = png_get_image_height(png, pngInfo);
ret->data = (uint32_t *)malloc((ret->width * ret->height) * sizeof(uint32_t));
png_bytep *rows = malloc(sizeof(png_bytep) * ret->height);
for(int i = 0; i < ret->height; i++)
rows[i] = malloc(png_get_rowbytes(png, pngInfo));
png_read_image(png, rows);
uint32_t *dataPtr = &ret->data[0];
for(int y = 0; y < ret->height; y++)
{
uint32_t *rowPtr = (uint32_t *)rows[y];
for(int x = 0; x < ret->width; x++)
*dataPtr++ = *rowPtr++;
}
for(int i = 0; i < ret->height; i++)
free(rows[i]);
free(rows);
png_destroy_read_struct(&png, &pngInfo, NULL);
fclose(pngIn);
return ret;
}
return NULL;
}
tex *texLoadJPEGFile(const char *path)
{
FILE *jpegIn = fopen(path, "rb");
if(jpegIn != NULL)
{
struct jpeg_decompress_struct jpegInfo;
struct jpeg_error_mgr error;
jpegInfo.err = jpeg_std_error(&error);
jpeg_create_decompress(&jpegInfo);
jpeg_stdio_src(&jpegInfo, jpegIn);
jpeg_read_header(&jpegInfo, true);
if(jpegInfo.jpeg_color_space == JCS_YCbCr)
jpegInfo.out_color_space = JCS_RGB;
tex *ret = malloc(sizeof(tex));
ret->width = jpegInfo.image_width;
ret->height = jpegInfo.image_height;
ret->data = (uint32_t *)malloc((ret->width * ret->height) * sizeof(uint32_t));
jpeg_start_decompress(&jpegInfo);
JSAMPARRAY row = malloc(sizeof(JSAMPROW));
row[0] = malloc(sizeof(JSAMPLE) * ret->width * 3);
uint32_t *dataPtr = &ret->data[0];
for(int y = 0; y < ret->height; y++)
{
jpeg_read_scanlines(&jpegInfo, row, 1);
uint8_t *jpegPtr = row[0];
for(int x = 0; x < ret->width; x++, jpegPtr += 3)
{
*dataPtr++ = (0xFF << 24 | jpegPtr[2] << 16 | jpegPtr[1] << 8 | jpegPtr[0]);
}
}
jpeg_finish_decompress(&jpegInfo);
jpeg_destroy_decompress(&jpegInfo);
free(row[0]);
free(row);
fclose(jpegIn);
return ret;
}
return NULL;
}
tex *texLoadJPEGMem(const uint8_t *jpegData, size_t jpegSize)
{
struct jpeg_decompress_struct jpegInfo;
struct jpeg_error_mgr error;
jpegInfo.err = jpeg_std_error(&error);
jpeg_create_decompress(&jpegInfo);
jpeg_mem_src(&jpegInfo, jpegData, jpegSize);
jpeg_read_header(&jpegInfo, true);
if(jpegInfo.jpeg_color_space == JCS_YCbCr)
jpegInfo.out_color_space = JCS_RGB;
tex *ret = malloc(sizeof(tex));
ret->width = jpegInfo.image_width;
ret->height = jpegInfo.image_height;
ret->data = (uint32_t *)malloc((ret->width * ret->height) * sizeof(uint32_t));
jpeg_start_decompress(&jpegInfo);
JSAMPARRAY row = malloc(sizeof(JSAMPARRAY));
row[0] = malloc(sizeof(JSAMPLE) * ret->width * 3);
uint32_t *dataPtr = &ret->data[0];
for(int y = 0; y < ret->height; y++)
{
jpeg_read_scanlines(&jpegInfo, row, 1);
uint8_t *jpegPtr = row[0];
for(int x = 0; x < ret->width; x++, jpegPtr += 3)
{
*dataPtr++ = (0xFF << 24 | jpegPtr[2] << 16 | jpegPtr[1] << 8 | jpegPtr[0]);
}
}
jpeg_finish_decompress(&jpegInfo);
jpeg_destroy_decompress(&jpegInfo);
free(row[0]);
free(row);
return ret;
}
void texDestroy(tex *t)
{
if(t->data != NULL)
free(t->data);
if(t != NULL)
free(t);
}
void texClearColor(tex *in, const color c)
{
uint32_t *dataPtr = &in->data[0];
for(int i = 0; i < in->width * in->height; i++)
*dataPtr++ = colorGetColor(c);
}
void texDraw(const tex *t, tex *target, int x, int y)
{
if(t->data != NULL)
{
color dataClr, fbClr;
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + t->height; tY++)
{
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + t->width; tX++, rowPtr++)
{
colorCreateFromU32(&dataClr, *dataPtr++);
colorCreateFromU32(&fbClr, *rowPtr);
*rowPtr = blend(dataClr, fbClr);
}
}
}
}
void texDrawNoAlpha(const tex *t, tex *target, int x, int y)
{
if(t->data != NULL)
{
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + t->height; tY++)
{
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + t->width; tX++)
{
*rowPtr++ = *dataPtr++;
}
}
}
}
void texDrawSkip(const tex *t, tex *target, int x, int y)
{
if(t->data != NULL)
{
uint32_t *dataPtr = &t->data[0];
color px1, px2, fbPx;
for(int tY = y; tY < y + (t->height / 2); tY++, dataPtr += t->width)
{
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + (t->width / 2); tX++, rowPtr++)
{
colorCreateFromU32(&px1, *dataPtr++);
colorCreateFromU32(&px2, *dataPtr++);
colorCreateFromU32(&fbPx, *rowPtr);
*rowPtr = blend(colorCreateTemp(smooth(px1, px2)), fbPx);
}
}
}
}
void texDrawSkipNoAlpha(const tex *t, tex *target, int x, int y)
{
if(t->data != NULL)
{
uint32_t *dataPtr = &t->data[0];
color px1, px2;
for(int tY = y; tY < y + (t->height / 2); tY++, dataPtr += t->width)
{
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + (t->width / 2); tX++, rowPtr++)
{
colorCreateFromU32(&px1, *dataPtr++);
colorCreateFromU32(&px2, *dataPtr++);
*rowPtr = smooth(px1, px2);
}
}
}
}
void texDrawInvert(const tex *t, tex *target, int x, int y, bool alpha)
{
if(t->data != NULL)
{
color dataClr, fbClr;
uint32_t *dataPtr = &t->data[0];
for(int tY = y; tY < y + t->height; tY++)
{
uint32_t *rowPtr = &target->data[tY * target->width + x];
for(int tX = x; tX < x + t->width; tX++, rowPtr++)
{
colorCreateFromU32(&dataClr, *dataPtr++);
colorInvert(&dataClr);
if(alpha)
colorCreateFromU32(&fbClr, *rowPtr);
*rowPtr = alpha ? blend(dataClr, fbClr) : colorGetColor(dataClr);
}
}
}
}
void texScaleToTex(const tex *in, tex *out, int scale)
{
for(int y = 0; y < in->height; y++)
{
for(int tY = y * scale; tY < (y * scale) + scale; tY++)
{
uint32_t *inPtr = &in->data[y * in->width];
for(int x = 0; x < in->width; x++, inPtr++)
{
for(int tX = x * scale; tX < (x * scale) + scale; tX++)
{
out->data[tY * (in->width * scale) + tX] = *inPtr;
}
}
}
}
}
void texDrawDirect(const tex *in, int x, int y)
{
uint32_t *fb = (uint32_t *)gfxGetFramebuffer(NULL, NULL);
uint32_t *dataPtr = &in->data[0];
for(int _y = y; _y < y + in->height; _y++)
{
uint32_t *rowPtr = &fb[_y * fbw + x];
for(int _x = x; _x < x + in->width; _x++)
{
*rowPtr++ = *dataPtr++;
}
}
}
font *fontLoadSharedFont(PlSharedFontType fontType)
{
PlFontData plFont;
if(R_FAILED(plGetSharedFontByType(&plFont, fontType)))
return NULL;
font *ret = malloc(sizeof(font));
if((ret->libRet = FT_Init_FreeType(&ret->lib)))
{
free(ret);
return NULL;
}
if((ret->faceRet = FT_New_Memory_Face(ret->lib, plFont.address, plFont.size, 0, &ret->face)))
{
free(ret);
return NULL;
}
ret->fntData = NULL;
return ret;
}
font *fontLoadTTF(const char *path)
{
font *ret = malloc(sizeof(font));
if((ret->libRet = FT_Init_FreeType(&ret->lib)))
{
free(ret);
return NULL;
}
FILE *ttf = fopen(path, "rb");
fseek(ttf, 0, SEEK_END);
size_t ttfSize = ftell(ttf);
fseek(ttf, 0, SEEK_SET);
ret->fntData = malloc(ttfSize);
fread(ret->fntData, 1, ttfSize, ttf);
fclose(ttf);
if((ret->faceRet = FT_New_Memory_Face(ret->lib, ret->fntData, ttfSize, 0, &ret->face)))
{
free(ret);
return NULL;
}
return ret;
}
void fontDestroy(font *f)
{
if(f->faceRet == 0)
FT_Done_Face(f->face);
if(f->libRet == 0)
FT_Done_FreeType(f->lib);
if(f->fntData != NULL)
free(f->fntData);
free(f);
}
tex *texGetFramebuffer()
{
return frameBuffer;
}

Some files were not shown because too many files have changed in this diff Show More