├── .clang-format ├── .github └── workflows │ └── main.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── TGAReader_LICENSE ├── include ├── ApplicationState.h ├── BackupSetList.h ├── LockingQueue.h ├── Metadata.h ├── cfg │ ├── BaseCfg.h │ ├── ExcludesCfg.h │ └── GlobalCfg.h ├── icon.h ├── menu │ ├── BRTitleSelectState.h │ ├── BackupSetListFilterState.h │ ├── BackupSetListState.h │ ├── BatchBackupState.h │ ├── BatchBackupTitleSelectState.h │ ├── BatchRestoreOptions.h │ ├── BatchRestoreState.h │ ├── ConfigMenuState.h │ ├── KeyboardState.h │ ├── MainMenuState.h │ ├── TitleOptionsState.h │ ├── TitleTaskState.h │ ├── WiiUTitleListState.h │ └── vWiiTitleListState.h ├── savemng.h ├── tga_reader.h ├── utils │ ├── Colors.h │ ├── DrawUtils.h │ ├── InputUtils.h │ ├── KeyboardUtils.h │ ├── LanguageUtils.h │ ├── StateUtils.h │ ├── StringUtils.h │ └── schrift.h └── version.h ├── meta ├── hbl │ ├── icon.png │ └── meta.xml └── wuhb │ ├── drc-splash.png │ ├── icon.png │ └── tv-splash.png ├── romfs └── languages │ ├── SChinese.json │ ├── TChinese.json │ ├── english.json │ ├── german.json │ ├── italian.json │ ├── japanese.json │ ├── korean.json │ ├── portuguese.json │ ├── russian.json │ └── spanish.json └── src ├── BackupSetList.cpp ├── Metadata.cpp ├── cfg ├── BaseCfg.cpp ├── ExcludesCfg.cpp └── GlobalCfg.cpp ├── main.cpp ├── menu ├── BRTitleSelectState.cpp ├── BackupSetListFilter.cpp ├── BackupSetListState.cpp ├── BatchBackupState.cpp ├── BatchBackupTitleSelectState.cpp ├── BatchRestoreOptions.cpp ├── BatchRestoreState.cpp ├── ConfigMenuState.cpp ├── KeyboardState.cpp ├── MainMenuState.cpp ├── TitleOptionsState.cpp ├── TitleTaskState.cpp ├── WiiUTitleListState.cpp └── vWiiTitleListState.cpp ├── savemng.cpp ├── tga_reader.cpp └── utils ├── DrawUtils.cpp ├── InputUtils.cpp ├── KeyboardUtils.cpp ├── LanguageUtils.cpp ├── StateUtils.cpp ├── StringUtils.cpp └── schrift.c /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | AccessModifierOffset: -4 3 | AlignAfterOpenBracket: Align 4 | AlignConsecutiveMacros: AcrossEmptyLinesAndComments 5 | AlignOperands: Align 6 | AllowAllArgumentsOnNextLine: false 7 | AllowAllConstructorInitializersOnNextLine: false 8 | AllowAllParametersOfDeclarationOnNextLine: false 9 | AllowShortBlocksOnASingleLine: Always 10 | AllowShortCaseLabelsOnASingleLine: false 11 | AllowShortFunctionsOnASingleLine: All 12 | AllowShortIfStatementsOnASingleLine: Always 13 | AllowShortLambdasOnASingleLine: All 14 | AllowShortLoopsOnASingleLine: true 15 | AlwaysBreakAfterReturnType: None 16 | AlwaysBreakTemplateDeclarations: Yes 17 | BreakBeforeBraces: Custom 18 | BraceWrapping: 19 | AfterCaseLabel: false 20 | AfterClass: false 21 | AfterControlStatement: Never 22 | AfterEnum: false 23 | AfterFunction: false 24 | AfterNamespace: false 25 | AfterUnion: false 26 | BeforeCatch: false 27 | BeforeElse: false 28 | IndentBraces: false 29 | SplitEmptyFunction: false 30 | SplitEmptyRecord: true 31 | BreakBeforeBinaryOperators: None 32 | BreakBeforeTernaryOperators: true 33 | BreakConstructorInitializers: BeforeColon 34 | BreakInheritanceList: BeforeColon 35 | ColumnLimit: 0 36 | CompactNamespaces: false 37 | ContinuationIndentWidth: 8 38 | IndentCaseLabels: true 39 | IndentPPDirectives: None 40 | IndentWidth: 4 41 | KeepEmptyLinesAtTheStartOfBlocks: true 42 | MaxEmptyLinesToKeep: 2 43 | NamespaceIndentation: All 44 | ObjCSpaceAfterProperty: false 45 | ObjCSpaceBeforeProtocolList: true 46 | PointerAlignment: Right 47 | ReflowComments: false 48 | SpaceAfterCStyleCast: true 49 | SpaceAfterLogicalNot: false 50 | SpaceAfterTemplateKeyword: false 51 | SpaceBeforeAssignmentOperators: true 52 | SpaceBeforeCpp11BracedList: false 53 | SpaceBeforeCtorInitializerColon: true 54 | SpaceBeforeInheritanceColon: true 55 | SpaceBeforeParens: ControlStatements 56 | SpaceBeforeRangeBasedForLoopColon: true 57 | SpaceInEmptyParentheses: false 58 | SpacesBeforeTrailingComments: 1 59 | SpacesInAngles: false 60 | SpacesInCStyleCastParentheses: false 61 | SpacesInContainerLiterals: false 62 | SpacesInParentheses: false 63 | SpacesInSquareBrackets: false 64 | TabWidth: 4 65 | UseTab: Never -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI-Release 2 | 3 | on: [ push, pull_request ] 4 | 5 | jobs: 6 | build-binary: 7 | runs-on: ubuntu-22.04 8 | steps: 9 | - name: Checkout 10 | uses: actions/checkout@v4 11 | with: 12 | fetch-depth: 0 13 | - name: Docker Layer Caching 14 | uses: ScribeMD/docker-cache@0.5.0 15 | continue-on-error: true 16 | id: cache 17 | with: 18 | key: savemii-docker-cache-${{ hashFiles('DockerFile')}} 19 | - name: Build artifacts 20 | run: | 21 | docker build . --file Dockerfile --tag builder 22 | docker run --rm -v ${PWD}:/project builder make release -j$(nproc) 23 | - name: Upload Aroma version 24 | uses: actions/upload-artifact@v4 25 | with: 26 | name: SaveMiiModWUTPort-Aroma 27 | path: build/Aroma/* 28 | if-no-files-found: warn 29 | - name: Upload HBL version 30 | uses: actions/upload-artifact@v4 31 | with: 32 | name: SaveMiiModWUTPort-HBL 33 | path: build/HBL/* 34 | if-no-files-found: warn 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | output 3 | tmp 4 | encryptKeyWith 5 | *.elf 6 | *.zip 7 | *.bat 8 | *.jar 9 | *.rpx 10 | TODO.txt 11 | .vscode 12 | *.wuhb 13 | .idea -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ghcr.io/wiiu-env/devkitppc:20241128 2 | 3 | COPY --from=ghcr.io/wiiu-env/libmocha:20240603 /artifacts $DEVKITPRO 4 | 5 | RUN git clone --recursive https://github.com/yawut/libromfs-wiiu --single-branch && \ 6 | cd libromfs-wiiu && \ 7 | make -j$(nproc) && \ 8 | make install && \ 9 | cd .. && \ 10 | rm -rf libromfs-wiiu 11 | 12 | WORKDIR /project 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------- 2 | .SUFFIXES: 3 | #------------------------------------------------------------------------------- 4 | 5 | ifeq ($(strip $(DEVKITPRO)),) 6 | $(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | 11 | #------------------------------------------------------------------------------- 12 | # APP_NAME sets the long name of the application 13 | # APP_SHORTNAME sets the short name of the application 14 | # APP_AUTHOR sets the author of the application 15 | #------------------------------------------------------------------------------- 16 | APP_NAME := SaveMii WUT Port 17 | APP_SHORTNAME := SaveMii 18 | APP_AUTHOR := DaThinkingChair,w3irDv 19 | 20 | include $(DEVKITPRO)/wut/share/wut_rules 21 | 22 | #------------------------------------------------------------------------------- 23 | # TARGET is the name of the output 24 | # BUILD is the directory where object files & intermediate files will be placed 25 | # SOURCES is a list of directories containing source code 26 | # DATA is a list of directories containing data files 27 | # INCLUDES is a list of directories containing header files 28 | # CONTENT is the path to the bundled folder that will be mounted as /vol/content/ 29 | # ICON is the game icon, leave blank to use default rule 30 | # TV_SPLASH is the image displayed during bootup on the TV, leave blank to use default rule 31 | # DRC_SPLASH is the image displayed during bootup on the DRC, leave blank to use default rule 32 | #------------------------------------------------------------------------------- 33 | TARGET := savemii 34 | BUILD := build 35 | SOURCES := src src/utils src/menu src/cfg 36 | DATA := data 37 | INCLUDES := include 38 | CONTENT := 39 | ICON := meta/wuhb/icon.png 40 | TV_SPLASH := meta/wuhb/tv-splash.png 41 | DRC_SPLASH := meta/wuhb/drc-splash.png 42 | ROMFS := romfs 43 | 44 | #------------------------------------------------------------------------------- 45 | # options for code generation 46 | #------------------------------------------------------------------------------- 47 | CFLAGS := -std=gnu2x -g -Wall -Ofast -ffunction-sections \ 48 | $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__ -D__wiiu__ 49 | 50 | CXXFLAGS := -std=gnu++20 -g -Wall -Wno-switch -Wno-format-overflow -Ofast -fpermissive -ffunction-sections \ 51 | $(MACHDEP) $(INCLUDE) -D__WIIU__ -D__WUT__ -D__wiiu__ 52 | 53 | ASFLAGS := -g $(ARCH) 54 | LDFLAGS = -g $(ARCH) $(RPXSPECS) -Wl,-Map,$(notdir $*.map) 55 | 56 | LIBS := -lwut -lmocha -ljansson 57 | 58 | include $(PORTLIBS_PATH)/wiiu/share/romfs-wiiu.mk 59 | CFLAGS += $(ROMFS_CFLAGS) 60 | CXXFLAGS += $(ROMFS_CFLAGS) 61 | LIBS += $(ROMFS_LIBS) 62 | OFILES += $(ROMFS_TARGET) 63 | 64 | #------------------------------------------------------------------------------- 65 | # list of directories containing libraries, this must be the top level 66 | # containing include and lib 67 | #------------------------------------------------------------------------------- 68 | LIBDIRS := $(PORTLIBS) $(WUT_ROOT) $(WUT_ROOT)/usr 69 | 70 | #------------------------------------------------------------------------------- 71 | # no real need to edit anything past this point unless you need to add additional 72 | # rules for different file extensions 73 | #------------------------------------------------------------------------------- 74 | ifneq ($(BUILD),$(notdir $(CURDIR))) 75 | #------------------------------------------------------------------------------- 76 | 77 | export OUTPUT := $(CURDIR)/$(TARGET) 78 | export TOPDIR := $(CURDIR) 79 | 80 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 81 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 82 | 83 | export DEPSDIR := $(CURDIR)/$(BUILD) 84 | 85 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 86 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 87 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 88 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 89 | 90 | #------------------------------------------------------------------------------- 91 | # use CXX for linking C++ projects, CC for standard C 92 | #------------------------------------------------------------------------------- 93 | ifeq ($(strip $(CPPFILES)),) 94 | #------------------------------------------------------------------------------- 95 | export LD := $(CC) 96 | #------------------------------------------------------------------------------- 97 | else 98 | #------------------------------------------------------------------------------- 99 | export LD := $(CXX) 100 | #------------------------------------------------------------------------------- 101 | endif 102 | #------------------------------------------------------------------------------- 103 | 104 | export OFILES_BIN := $(addsuffix .o,$(BINFILES)) 105 | export OFILES_SRC := $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 106 | export OFILES := $(OFILES_BIN) $(OFILES_SRC) 107 | export HFILES_BIN := $(addsuffix .h,$(subst .,_,$(BINFILES))) 108 | 109 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 110 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 111 | -I$(CURDIR)/$(BUILD) 112 | 113 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 114 | 115 | ifneq (,$(strip $(CONTENT))) 116 | export APP_CONTENT := $(TOPDIR)/$(CONTENT) 117 | endif 118 | 119 | ifneq (,$(strip $(ICON))) 120 | export APP_ICON := $(TOPDIR)/$(ICON) 121 | else ifneq (,$(wildcard $(TOPDIR)/$(TARGET).png)) 122 | export APP_ICON := $(TOPDIR)/$(TARGET).png 123 | else ifneq (,$(wildcard $(TOPDIR)/icon.png)) 124 | export APP_ICON := $(TOPDIR)/icon.png 125 | endif 126 | 127 | ifneq (,$(strip $(TV_SPLASH))) 128 | export APP_TV_SPLASH := $(TOPDIR)/$(TV_SPLASH) 129 | else ifneq (,$(wildcard $(TOPDIR)/tv-splash.png)) 130 | export APP_TV_SPLASH := $(TOPDIR)/tv-splash.png 131 | else ifneq (,$(wildcard $(TOPDIR)/splash.png)) 132 | export APP_TV_SPLASH := $(TOPDIR)/splash.png 133 | endif 134 | 135 | ifneq (,$(strip $(DRC_SPLASH))) 136 | export APP_DRC_SPLASH := $(TOPDIR)/$(DRC_SPLASH) 137 | else ifneq (,$(wildcard $(TOPDIR)/drc-splash.png)) 138 | export APP_DRC_SPLASH := $(TOPDIR)/drc-splash.png 139 | else ifneq (,$(wildcard $(TOPDIR)/splash.png)) 140 | export APP_DRC_SPLASH := $(TOPDIR)/splash.png 141 | endif 142 | 143 | .PHONY: $(BUILD) clean all 144 | 145 | #------------------------------------------------------------------------------- 146 | all: $(BUILD) 147 | 148 | $(BUILD): 149 | @$(shell [ ! -d $(BUILD) ] && mkdir -p $(BUILD)) 150 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 151 | 152 | #------------------------------------------------------------------------------- 153 | clean: 154 | @echo clean ... 155 | @rm -fr $(BUILD) $(TARGET).wuhb $(TARGET).rpx $(TARGET).elf SaveMiiModWUTPort *.zip 156 | 157 | #------------------------------------------------------------------------------- 158 | release: $(BUILD) 159 | @mkdir -p build/Aroma/wiiu/apps/SaveMiiModWUTPort 160 | @mkdir -p build/HBL/wiiu/apps/SaveMiiModWUTPort 161 | @rm -rf build/Aroma/wiiu/apps/SaveMiiModWUTPort/* 162 | @rm -rf build/HBL/wiiu/apps/SaveMiiModWUTPort/* 163 | @cp savemii.rpx build/HBL/wiiu/apps/SaveMiiModWUTPort 164 | @cp meta/hbl/icon.png build/HBL/wiiu/apps/SaveMiiModWUTPort 165 | @cp meta/hbl/meta.xml build/HBL/wiiu/apps/SaveMiiModWUTPort 166 | @cp savemii.wuhb build/Aroma/wiiu/apps/SaveMiiModWUTPort 167 | @zip -9 -r SaveMiiModWUTPort-HBL.zip build/HBL 168 | @zip -9 -r SaveMiiModWUTPort-Aroma.zip build/Aroma 169 | #------------------------------------------------------------------------------- 170 | else 171 | .PHONY: all 172 | 173 | DEPENDS := $(OFILES:.o=.d) 174 | 175 | #------------------------------------------------------------------------------- 176 | # main targets 177 | #------------------------------------------------------------------------------- 178 | all : $(OUTPUT).wuhb 179 | 180 | $(OUTPUT).wuhb : $(OUTPUT).rpx 181 | $(OUTPUT).rpx : $(OUTPUT).elf 182 | $(OUTPUT).elf : $(OFILES) 183 | 184 | $(OFILES_SRC) : $(HFILES_BIN) 185 | 186 | #------------------------------------------------------------------------------- 187 | # you need a rule like this for each extension you use as binary data 188 | #------------------------------------------------------------------------------- 189 | %.bin.o %_bin.h : %.bin 190 | #------------------------------------------------------------------------------- 191 | @echo $(notdir $<) 192 | @$(bin2o) 193 | 194 | -include $(DEPENDS) 195 | 196 | #------------------------------------------------------------------------------- 197 | endif 198 | #------------------------------------------------------------------------------- 199 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SaveMii WUT Port 2 | 3 | Original by Ryuzaki-MrL WUT Port by me 4 | 5 | WiiU/vWii Save Manager 6 | 7 | This homebrew allows you to backup your Wii U and vWii savegames to the SD card and also restore them. Up to 256 backups 8 | can be made per title. Backups are stored in sd:/wiiu/backups. 9 | 10 | For sorting Titles press R to change sorting method and press L to change between descending and ascending. 11 | 12 | Use it at your own risk and please report any issues that may occur. 13 | 14 | ## Quick Notes 15 | 16 | Move across screen by using Up/Down D-Pad buttons. Cycle between options by using Left/Right D-Pad buttons. "A" to select a task / enter a menu. "B" to go back to the previous menu. Special functions can be accessed by using "X/Y/+/-" buttons, as described at the bottom line in each menu. 17 | 18 | ### Wii U Title Management / vWii Title Management 19 | 20 | Allows you to backup/restore/wipe individual titles. 21 | 22 | 1. First select the title you want to manage. 23 | 1. Wii U titles: If the title has not been initialized (you have not created an initial save by playing to it beforehand) it will be marked as "Not init" and will appear in yellow. You can try to manage it (restore from a previous backup), but the outcome is uncertain. It is recommended to first play and create "real" savedata before trying to restore any backup. 24 | 1. An special case of this are vWii injects. They have both a Wii U title with no savedata that will appear in "Wii U Title Management" marked as "Not init", and a vWii title where the game's savedata is that will appear in vWii Title Management after you play it and create an initial game savedata. Savedata for these titles must be managed from the vWii Management tasks. Just in case, Savemii allows you to manage the Wii U title portion, but it usually doesn't contain any savedata. 25 | 2. Select the task you want to do: 26 | 1. Backup: Copy savedata from USB/NAND to SD 27 | 2. Restore: Copy savedata from SD to USB/NAND 28 | 3. Wipe: Delete savedata from USB/NAND 29 | 4. Export / Import to Loadiine: Legacy options to manage Loadiine savedata 30 | 5. Copy to other Device: If savedata for a title is present in USB and NAND, copy it from one storage to the other 31 | 32 | #### Backup 33 | 1. Select a slot to store the savedata. You can select any number from 0 to 255, each one representing a different folder in the SD card. Individual backups will always be stored in the `Root backupSet`. 34 | 2. For Wii U titles, select which data to save: 35 | 1. All users: Recommended option. Will backup all game data. 36 | 2. From user: xxxxxxxx. Will only backup the data for the specified user/profile. In this case, you must also specify if you want to save the "common" data or not. "Common" savedata is data shared by all profiles. Titles can have common save data, profile savedata or both. 37 | 3. Press "A" to initiate the backup. After the backup is done, you can tag the slot with a meaningful name pressing "+" button while you are in the backup menu. If the slot is unneeded, you can delete it by pressing "-" button. 38 | 39 | *Wii U titles savedata layout:* 40 | ``` 41 | sd:/wiiu/backups/ # Root backupSet 42 | xxxxxxxxyyyyyyyy/ # Title Id 43 | 0/ 44 | saveMiiMeta.json 45 | 80000001/ # one folder for each profile 46 | ... # savedata 47 | 80000002/ 48 | ... 49 | ... 50 | common/ 51 | ... 52 | 1/ # one folder for each slot 53 | ... 54 | ``` 55 | For vWii titles, savedata is directly under the slot folder. 56 | 57 | #### Restore 58 | 1. Select a slot to get the data from. If you haven't selected any backupSet, the data from the `Root backupSet` (the one where the manual backups are always stored) is used. But you can also use data from any batch backupSet, by pressing the "X" button and selecting the backupSet you want to use. Notice that the last backupSet you previously selected in any task (Batch Restore or BackupSet Management) will be the one used here by default. BackupSets can be tagged by pressing "+" button in the BackupSet List Menu, or from the BackupSet Management in Main menu. 59 | To identify which data the slot contains: If the slot has been tagged, you will see its tag next to the slot number. On the top screen line, you will see which backupSet is being used. And at the last screen line, you can see when the savedata were taken, and from which console. 60 | 2. For Wii U titles, select witch data to restore: 61 | 1. `From: All users / To: Same user than Source` 62 | This will restore all save data (profiles+common) from the selected slot keeping the same userid that was used to backup the data. This option can only be used to restore previous savedata from the same console, or if the profile ids in the new console are identical to the ones in the source console. If profile ids from source and target differ, you must use the next option. 63 | 2. `From: select source user / To: select target user`. This will copy savedata from the specified source profile id in the slot backup to the specified target profile id in the console. You can specify if copy common savedata or not. 64 | If you are just copying the savedata from one profile id to a different one in the same console, choose `copy common savedata: no`. If you are restoring to a new console with different profile ids, just choose `copy common savedata: yes` once for any of the profile ids, and copy the rest of profiles with `copy common savedata: no` 65 | 3. Press "A" to initiate the restore. 66 | 67 | #### Wipe 68 | Sometimes you will need to wipe savedata in the console before restoring a previous backup: If a restore is unsuccesful, you can try to wipe previous data before attempting a new restore. Options are the same than in the *Backup* task, but now refer to savedata for the specified title in the NAND or in the USB. 69 | 70 | #### Copy to other device 71 | If a title has savedata in the NAND and in the USB, you can copy it between both storages. Options are the same than in the *Restore* task. 72 | 73 | ### Batch Backup 74 | 75 | You can backup savedata for all Wii U titles and all Wii titles at once using this tasks. Savedata will be stored in a "Backup set" in the `batch` directori, and can after be used to restore individual titles or to batch restore all of them. 76 | BackupSets can be tagged by pressing "+" button in the BackupSet List menu or by entering in the menu Backupset Management from the Main menu. 77 | 78 | ``` 79 | sd:/wiiu/backups/batch/ 80 | ${timestamp}/ # batch backupSet 81 | saveMiiMeta.json 82 | xxxxxxxxyyyyyyyy/ # one folder for each title 83 | 0/ # slot containing USB or NAND savedata for the title 84 | saveMiiMeta.json 85 | 80000001/ 86 | ... 87 | 80000002/ 88 | ... 89 | ... one folder for each profile 90 | common/ 91 | ... 92 | 1/ # slot containing NAND savedata for titles simultaneously installed in USB and NAND 93 | ... 94 | xxxxxxxxxyyyyyyyy/ 95 | 0/ 96 | ... 97 | ``` 98 | 99 | ### Batch Restore 100 | 101 | This task allows you to restore the savedata for all titles already installed in the Wii U or in the vWii from a batch backupSet, 102 | 1. Select wether you want to restore Wii U titles or vWii titles 103 | 2. Select the backupSet you want to restore from 104 | 3. Select wich data to restore. Options are the same than in the *Restore* task. You can also choose if you want to perform a full backup (recommended) or to wipe data before restoring it. 105 | 4. The list of all titles that are installed, that have a backup in the backupset, and that match the savedata criteria choosen in the previous step will appear. You can select / deselect which titles to restore. Titles with "Not Init" will be skipped by default. 106 | 5. Once you have reviewed the list of titles to be restored, press "A". A summary screen will appear, and if it is OK, you can initiate the restore. 107 | 6. Once the restore is completed, a summary screen will show the number of sucess/failed/skipped titles. 108 | 7. The list of all titles will appear again, now showing the restored status. You can try to select failed titles and restore them again to see what the error is. Succesfully restored titles will be skipped. 109 | 110 | ### Backupset management 111 | In this menu you can tag backupsets ("+") or delete the ones you don't need ("-"). You can also set the one you want to use to restore savedata ("A"). 112 | 113 | 114 | ---- 115 | 116 | 117 | Reasons to use this over original mod: 118 | 119 | - Faster copy speeds 120 | - VC injects are shown 121 | - If VC is vWii, the user is warned to go to the vWii saves section instead 122 | - Demo support 123 | - Fixes issues present in the mod version 124 | - Shows useful info about the saves like its date and time of creation 125 | 126 | Credits: 127 | 128 | - Bruno Vinicius, for the icon 129 | - Maschell, for libmocha and countless help 130 | - Crementif for helping with freetype 131 | - V10lator for helping with a lot of stuff 132 | - Vague Rant for testing 133 | -------------------------------------------------------------------------------- /TGAReader_LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Kenji Sasaki 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /include/ApplicationState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define MIN_MENU_ID 0 6 | #define MAX_MENU_ID 3 7 | 8 | enum Task { 9 | backup = 0, 10 | restore = 1, 11 | wipe = 2, 12 | importLoadiine = 3, 13 | exportLoadiine = 4, 14 | copytoOtherDevice = 5 15 | }; 16 | 17 | class ApplicationState { 18 | public: 19 | enum eSubState { 20 | SUBSTATE_RUNNING, 21 | SUBSTATE_RETURN, 22 | }; 23 | 24 | enum eSubstateCalled { 25 | NONE 26 | }; 27 | 28 | virtual void render() = 0; 29 | virtual eSubState update(Input *input) = 0; 30 | 31 | }; -------------------------------------------------------------------------------- /include/BackupSetList.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class BSMetadataValues { 9 | friend class BSMetadata; 10 | friend class BackupSetList; 11 | public: 12 | 13 | template 14 | class attr { 15 | public: 16 | std::set range; 17 | std::set::iterator iterator; 18 | }; 19 | attr> year; 20 | attr> month; 21 | attr> serialId; 22 | attr> tag; 23 | 24 | template 25 | static void Right (T & metadataAttrValues); 26 | 27 | template 28 | static void Left (T & metadataAttrValues); 29 | 30 | void resetFilter(); 31 | 32 | }; 33 | 34 | class BSMetadata { 35 | public: 36 | friend class BackupSetItem; 37 | friend class BackupSetList; 38 | BSMetadata(std::string year = "*", std::string month = "*", 39 | std::string serialId = "*", std::string tag = "*") : 40 | year(year),month(month),serialId(serialId),tag(tag) {}; 41 | BSMetadata(BSMetadataValues & bsMetadataValues) : 42 | year(*(bsMetadataValues.year.iterator)),month(*(bsMetadataValues.month.iterator)), 43 | serialId(*(bsMetadataValues.serialId.iterator)),tag(*(bsMetadataValues.tag.iterator)) {}; 44 | private: 45 | std::string year; 46 | std::string month; 47 | std::string serialId; 48 | std::string tag; 49 | }; 50 | 51 | class BackupSetItem { 52 | public: 53 | friend class BackupSetList; 54 | BackupSetItem(std::string entryPath,BSMetadata bsItemMetadata) : 55 | entryPath(entryPath),bsItemMetadata(bsItemMetadata) {}; 56 | private: 57 | std::string entryPath; 58 | BSMetadata bsItemMetadata; 59 | }; 60 | 61 | struct BackupSetItemView { 62 | std::string entryPath; 63 | std::string serialId; 64 | std::string tag; 65 | }; 66 | 67 | 68 | class BackupSetList { 69 | public: 70 | friend class BackupSetListState; 71 | friend class BackupSetListFilterState; 72 | BackupSetList() {}; 73 | BackupSetList(const char *backupSetListRoot); 74 | static std::unique_ptr currentBackupSetList; 75 | 76 | void sort(bool sortAscending = false); 77 | static bool getSortAscending() { return sortAscending;}; 78 | std::string at(int i); 79 | std::string getSerialIdAt(int i); 80 | std::string getStretchedSerialIdAt(int i); 81 | std::string getTagAt(int i); 82 | void setTagBSVAt(int i, const std::string & tag); 83 | void setTagBSAt(int i, const std::string & tag); 84 | void add(std::string entryPath,std::string serialId,std::string tag); 85 | 86 | int getSizeView() { return this->entriesView;}; 87 | int getSize() { return this->entries;}; 88 | 89 | void filter(); 90 | void filter(BSMetadata filterDef); 91 | void resetTagRange(); 92 | BSMetadataValues *getBSMetadataValues() {return &bsMetadataValues; }; 93 | 94 | static const std::string ROOT_BS; 95 | static std::string getBackupSetSubPath() { return backupSetSubPath; }; 96 | static std::string getBackupSetPath() { return currentBackupSetList->backupSetListRoot+backupSetSubPath; }; 97 | static std::string getBackupSetEntry() { return backupSetEntry; }; 98 | static std::string getBackupSetSubPath(int i); 99 | static void setBackupSetEntry(int i); 100 | static void setBackupSetSubPath(); 101 | static void initBackupSetList(); 102 | static void setBackupSetSubPathToRoot() { backupSetSubPath = "/"; } 103 | static void setBackupSetToRoot() { setBackupSetEntry(0); setBackupSetSubPathToRoot();} 104 | static void saveBackupSetSubPath() { savedBackupSetSubPath = backupSetSubPath; } 105 | static void restoreBackupSetSubPath() { backupSetSubPath = savedBackupSetSubPath; } 106 | static bool getIsInitializationRequired() { return isInitializationRequired; } 107 | static void setIsInitializationRequired(bool isInitializationRequired_) { 108 | BackupSetList::isInitializationRequired = isInitializationRequired_; 109 | } 110 | 111 | private: 112 | static bool sortAscending; 113 | std::vector backupSetsView; 114 | std::vector backupSets; 115 | std::vector serialIds; 116 | std::vector tags; 117 | std::vector v2b; 118 | BSMetadataValues bsMetadataValues; 119 | int entriesView; 120 | int entries; 121 | std::string backupSetListRoot; 122 | static std::string backupSetSubPath; 123 | static std::string backupSetEntry; 124 | static std::string savedBackupSetSubPath; 125 | inline static bool isInitializationRequired = false; 126 | 127 | }; 128 | 129 | 130 | -------------------------------------------------------------------------------- /include/LockingQueue.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | template 8 | class LockingQueue { 9 | public: 10 | void push(T const &_data) { 11 | { 12 | std::lock_guard lock(guard); 13 | queue.push(_data); 14 | } 15 | signal.notify_one(); 16 | } 17 | 18 | bool empty() const { 19 | std::lock_guard lock(guard); 20 | return queue.empty(); 21 | } 22 | 23 | bool tryPop(T &_value) { 24 | std::lock_guard lock(guard); 25 | if (queue.empty()) { 26 | return false; 27 | } 28 | 29 | _value = queue.front(); 30 | queue.pop(); 31 | return true; 32 | } 33 | 34 | void waitAndPop(T &_value) { 35 | std::unique_lock lock(guard); 36 | while (queue.empty()) { 37 | signal.wait(lock); 38 | } 39 | 40 | _value = queue.front(); 41 | queue.pop(); 42 | } 43 | 44 | bool tryWaitAndPop(T &_value, int _milli) { 45 | std::unique_lock lock(guard); 46 | while (queue.empty()) { 47 | signal.wait_for(lock, std::chrono::milliseconds(_milli)); 48 | return false; 49 | } 50 | 51 | _value = queue.front(); 52 | queue.pop(); 53 | return true; 54 | } 55 | 56 | private: 57 | std::queue queue; 58 | mutable std::mutex guard; 59 | std::condition_variable signal; 60 | }; -------------------------------------------------------------------------------- /include/Metadata.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | //#include 6 | #include 7 | #include 8 | 9 | class Metadata { 10 | public: 11 | Metadata(uint32_t high, uint32_t low, uint8_t s) : highID(high), 12 | lowID(low), 13 | slot(s), 14 | path (getDynamicBackupPath(highID, lowID, slot).append("/savemiiMeta.json")), 15 | Date({}), 16 | storage({}), 17 | serialId(this->unknownSerialId), 18 | tag({}) { } 19 | 20 | Metadata(uint32_t high, uint32_t low, uint8_t s, std::string datetime) : highID(high), 21 | lowID(low), 22 | slot(s), 23 | path (getBatchBackupPath(highID, lowID, slot, datetime).append("/savemiiMeta.json")), 24 | Date({}), 25 | storage({}), 26 | serialId(this->unknownSerialId), 27 | tag({}) { } 28 | 29 | // guess date from batchBackupRoot, to infer a savemiiMeta.json for <1.6.4 batchBackups 30 | Metadata(const std::string & path) : storage({}), 31 | serialId(this->unknownSerialId), 32 | tag({}) { 33 | Date = path.substr(path.length()-17,17); 34 | if (Date.substr(0,2) != "20") 35 | Date=""; 36 | this->path = path + ("/savemiiMeta.json"); 37 | } 38 | 39 | Metadata(const std::string & datetime, const std::string & storage, const std::string & serialId,const std::string & tag ) : 40 | Date(datetime), 41 | storage(storage), 42 | serialId(serialId), 43 | tag(tag) { 44 | path = getBatchBackupPathRoot(datetime)+"/savemiiMeta.json"; 45 | } 46 | 47 | 48 | bool read(); 49 | bool write(); 50 | std::string simpleFormat(); 51 | std::string get(); 52 | bool set(const std::string &date,bool isUSB); 53 | static std::string thisConsoleSerialId; 54 | static std::string unknownSerialId; 55 | std::string getDate() { return Date;}; 56 | std::string getTag() { return tag;}; 57 | void setTag(std::string tag_) { this->tag = tag_;}; 58 | std::string getSerialId() { return serialId;}; 59 | 60 | private: 61 | uint32_t highID; 62 | uint32_t lowID; 63 | uint8_t slot; 64 | std::string path; 65 | 66 | std::string Date; 67 | std::string storage; 68 | std::string serialId; 69 | std::string tag; 70 | }; 71 | 72 | -------------------------------------------------------------------------------- /include/cfg/BaseCfg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | class BaseCfg { 10 | 11 | public: 12 | BaseCfg(const std::string &cfg); 13 | 14 | bool init(); 15 | 16 | virtual bool mkJsonCfg() = 0; 17 | bool saveFile(); 18 | bool save(); 19 | 20 | virtual bool parseJsonCfg() = 0; 21 | bool readFile(); 22 | bool read(); 23 | 24 | virtual bool applyConfig() = 0; 25 | virtual bool getConfig() = 0; 26 | 27 | protected: 28 | std::string cfg; 29 | std::string cfgFile; 30 | char *configString; 31 | 32 | bool initialized = false; 33 | 34 | inline static std::string cfgPath { "fs:/vol/external01/wiiu/backups/saveMiiconfig" } ; 35 | 36 | 37 | }; -------------------------------------------------------------------------------- /include/cfg/ExcludesCfg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | struct titleID { 7 | uint32_t highID; 8 | uint32_t lowID; 9 | bool isTitleOnUSB; 10 | }; 11 | 12 | class ExcludesCfg : public BaseCfg { 13 | 14 | public: 15 | 16 | ExcludesCfg(const std::string & cfg,Title* titles , int titlesCount); 17 | 18 | virtual bool mkJsonCfg(); 19 | virtual bool parseJsonCfg(); 20 | 21 | bool applyConfig(); 22 | 23 | int parseExcludeJson(json_t* excludes); 24 | bool getConfig(); 25 | 26 | inline static std::unique_ptr wiiuExcludes = nullptr; 27 | inline static std::unique_ptr wiiExcludes = nullptr; 28 | 29 | private: 30 | 31 | std::vector titlesID; 32 | 33 | Title *titles = nullptr; 34 | int titlesCount = 0; 35 | 36 | }; -------------------------------------------------------------------------------- /include/cfg/GlobalCfg.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | 7 | class GlobalCfg : public BaseCfg { 8 | 9 | friend class ConfigMenuState; 10 | 11 | public: 12 | 13 | GlobalCfg(const std::string & cfg); 14 | 15 | virtual bool mkJsonCfg(); 16 | virtual bool parseJsonCfg(); 17 | 18 | bool applyConfig(); 19 | bool getConfig(); 20 | 21 | inline static std::unique_ptr global = nullptr; 22 | 23 | bool getAlwaysApplyExcludes() { return alwaysApplyExcludes;}; 24 | 25 | private: 26 | 27 | Swkbd_LanguageType Language; 28 | bool alwaysApplyExcludes; 29 | 30 | }; -------------------------------------------------------------------------------- /include/menu/BRTitleSelectState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class BRTitleSelectState : public ApplicationState { 11 | public: 12 | BRTitleSelectState(int sduser, int wiiuuser, bool common, bool wipeBeforeRestore, bool fullBackup,Title *titles, int titlesCount, bool isWiiUBatchRestore); 13 | 14 | enum eState { 15 | STATE_BATCH_RESTORE_TITLE_SELECT, 16 | STATE_DO_SUBSTATE, 17 | }; 18 | 19 | void render() override; 20 | ApplicationState::eSubState update(Input *input) override; 21 | 22 | private: 23 | std::unique_ptr subState{}; 24 | eState state = STATE_BATCH_RESTORE_TITLE_SELECT; 25 | 26 | 27 | int sduser; 28 | int wiiuuser; 29 | bool common; 30 | bool wipeBeforeRestore; 31 | bool fullBackup; 32 | Title *titles; 33 | int titlesCount; 34 | bool isWiiUBatchRestore; 35 | 36 | 37 | std::vector sortNames = {LanguageUtils::gettext("None"), 38 | LanguageUtils::gettext("Name"), 39 | LanguageUtils::gettext("Storage"), 40 | LanguageUtils::gettext("Strg+Nm")}; 41 | 42 | int titleSort = 1; 43 | int scroll = 0; 44 | int cursorPos = 0; 45 | bool sortAscending = true; 46 | int targ = 0; 47 | 48 | bool noTitles = false; 49 | 50 | std::vector c2t; 51 | int candidatesCount; 52 | 53 | void updateC2t(); 54 | 55 | std::vector titleStateAfterBR = { 56 | " ", 57 | " > Aborted", 58 | " > OK", 59 | " > WR", 60 | " > KO" 61 | }; 62 | }; -------------------------------------------------------------------------------- /include/menu/BackupSetListFilterState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | 10 | 11 | class BackupSetListFilterState : public ApplicationState { 12 | public: 13 | BackupSetListFilterState(std::unique_ptr & backupSetList) : 14 | backupSetList(backupSetList) {}; 15 | enum eState { 16 | STATE_BACKUPSET_FILTER, 17 | STATE_DO_SUBSTATE, 18 | }; 19 | 20 | void render() override; 21 | ApplicationState::eSubState update(Input *input) override; 22 | 23 | private: 24 | std::unique_ptr subState{}; 25 | eState state = STATE_BACKUPSET_FILTER; 26 | 27 | std::unique_ptr & backupSetList; 28 | int entrycount = 4; 29 | int cursorPos = 0; 30 | }; -------------------------------------------------------------------------------- /include/menu/BackupSetListState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class BackupSetListState : public ApplicationState { 9 | public: 10 | BackupSetListState(); 11 | BackupSetListState(Title *titles, int titlesCount, bool isWiiUBatchRestore); 12 | 13 | static void resetCursorPosition(); 14 | static void resetCursorAndScroll(); 15 | enum eState { 16 | STATE_BACKUPSET_MENU, 17 | STATE_DO_SUBSTATE, 18 | }; 19 | enum eSubstateCalled { 20 | NONE, 21 | STATE_BACKUPSET_FILTER, 22 | STATE_KEYBOARD 23 | }; 24 | 25 | void render() override; 26 | ApplicationState::eSubState update(Input *input) override; 27 | 28 | private: 29 | std::unique_ptr subState{}; 30 | eState state = STATE_BACKUPSET_MENU; 31 | eSubstateCalled substateCalled = NONE; 32 | bool finalScreen; 33 | 34 | bool sortAscending; 35 | 36 | static int cursorPos; 37 | static int scroll; 38 | 39 | std::string backupSetListRoot; 40 | 41 | std::string tag; 42 | std::string newTag; 43 | 44 | Title *titles; 45 | int titlesCount; 46 | 47 | bool isWiiUBatchRestore; 48 | }; -------------------------------------------------------------------------------- /include/menu/BatchBackupState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class BatchBackupState : public ApplicationState { 9 | public: 10 | BatchBackupState(Title *wiiutitles, Title *wiititles, int wiiuTitlesCount, int vWiiTitlesCount) : wiiutitles(wiiutitles), 11 | wiititles(wiititles), 12 | wiiuTitlesCount(wiiuTitlesCount), 13 | vWiiTitlesCount(vWiiTitlesCount) {} 14 | enum eState { 15 | STATE_BATCH_BACKUP_MENU, 16 | STATE_DO_SUBSTATE, 17 | }; 18 | 19 | void render() override; 20 | ApplicationState::eSubState update(Input *input) override; 21 | 22 | 23 | private: 24 | std::unique_ptr subState{}; 25 | eState state = STATE_BATCH_BACKUP_MENU; 26 | 27 | Title *wiiutitles; 28 | Title *wiititles; 29 | 30 | int wiiuTitlesCount; 31 | int vWiiTitlesCount; 32 | }; -------------------------------------------------------------------------------- /include/menu/BatchBackupTitleSelectState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class BatchBackupTitleSelectState : public ApplicationState { 12 | public: 13 | BatchBackupTitleSelectState(Title *titles, int titlesCount, bool isWiiUBatchBackup,std::unique_ptr & excludes); 14 | 15 | enum eState { 16 | STATE_BATCH_BACKUP_TITLE_SELECT, 17 | STATE_DO_SUBSTATE, 18 | }; 19 | 20 | void render() override; 21 | ApplicationState::eSubState update(Input *input) override; 22 | 23 | private: 24 | std::unique_ptr subState{}; 25 | eState state = STATE_BATCH_BACKUP_TITLE_SELECT; 26 | 27 | Title *titles; 28 | int titlesCount; 29 | bool isWiiUBatchBackup; 30 | 31 | std::vector sortNames = {LanguageUtils::gettext("None"), 32 | LanguageUtils::gettext("Name"), 33 | LanguageUtils::gettext("Storage"), 34 | LanguageUtils::gettext("Strg+Nm")}; 35 | 36 | int titleSort = 1; 37 | int scroll = 0; 38 | int cursorPos = 0; 39 | bool sortAscending = true; 40 | int targ = 0; 41 | 42 | bool noTitles = false; 43 | 44 | std::vector c2t; 45 | int candidatesCount; 46 | 47 | void updateC2t(); 48 | 49 | std::vector titleStateAfterBR = { 50 | " ", 51 | " > Aborted", 52 | " > OK", 53 | " > WR", 54 | " > KO" 55 | }; 56 | 57 | std::unique_ptr & excludes; 58 | 59 | }; -------------------------------------------------------------------------------- /include/menu/BatchRestoreOptions.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class BatchRestoreOptions : public ApplicationState { 11 | public: 12 | BatchRestoreOptions(Title *titles, int titlesCount, bool isWiiUBatchRestore); 13 | 14 | enum eState { 15 | STATE_BATCH_RESTORE_OPTIONS_MENU, 16 | STATE_DO_SUBSTATE, 17 | }; 18 | 19 | void render() override; 20 | ApplicationState::eSubState update(Input *input) override; 21 | std::string tag; 22 | 23 | private: 24 | std::unique_ptr subState{}; 25 | eState state = STATE_BATCH_RESTORE_OPTIONS_MENU; 26 | 27 | int8_t wiiuuser = -1; 28 | int8_t sduser = -1; 29 | bool common = false; 30 | 31 | bool wipeBeforeRestore = true; 32 | bool fullBackup = true; 33 | std::set> batchSDUsers; 34 | 35 | Title *titles; 36 | int titlesCount = 0; 37 | 38 | int cursorPos; 39 | int minCursorPos; 40 | 41 | bool isWiiUBatchRestore; 42 | 43 | 44 | }; -------------------------------------------------------------------------------- /include/menu/BatchRestoreState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class BatchRestoreState : public ApplicationState { 9 | public: 10 | BatchRestoreState(Title *wiiutitles, Title *wiititles, int wiiuTitlesCount, int vWiiTitlesCount) : wiiutitles(wiiutitles), 11 | wiititles(wiititles), 12 | wiiuTitlesCount(wiiuTitlesCount), 13 | vWiiTitlesCount(vWiiTitlesCount) {} 14 | enum eState { 15 | STATE_BATCH_RESTORE_MENU, 16 | STATE_DO_SUBSTATE, 17 | }; 18 | 19 | void render() override; 20 | ApplicationState::eSubState update(Input *input) override; 21 | std::string tag; 22 | 23 | private: 24 | std::unique_ptr subState{}; 25 | eState state = STATE_BATCH_RESTORE_MENU; 26 | 27 | Title *wiiutitles; 28 | Title *wiititles; 29 | 30 | int wiiuTitlesCount; 31 | int vWiiTitlesCount; 32 | }; -------------------------------------------------------------------------------- /include/menu/ConfigMenuState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class ConfigMenuState : public ApplicationState { 8 | public: 9 | enum eState { 10 | STATE_CONFIG_MENU, 11 | STATE_DO_SUBSTATE, 12 | }; 13 | 14 | void render() override; 15 | ApplicationState::eSubState update(Input *input) override; 16 | 17 | private: 18 | std::unique_ptr subState{}; 19 | eState state = STATE_CONFIG_MENU; 20 | }; -------------------------------------------------------------------------------- /include/menu/KeyboardState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class KeyboardState : public ApplicationState { 9 | public: 10 | KeyboardState(std::string & input) : input(input) { 11 | this->keyboard = std::make_unique(); 12 | this->cursorPosX = this->keyboard->column; 13 | this->cursorPosY = this->keyboard->row; 14 | } 15 | enum eState { 16 | STATE_KEYBOARD, 17 | STATE_DO_SUBSTATE, 18 | }; 19 | 20 | void render() override; 21 | ApplicationState::eSubState update(Input *input) override; 22 | 23 | private: 24 | std::unique_ptr subState{}; 25 | eState state = STATE_KEYBOARD; 26 | 27 | std::unique_ptr keyboard; 28 | 29 | int entrycount = 4; 30 | int cursorPosX = 0; 31 | int cursorPosY = 0; 32 | std::string & input; 33 | }; -------------------------------------------------------------------------------- /include/menu/MainMenuState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class MainMenuState : public ApplicationState { 9 | public: 10 | MainMenuState(Title *wiiutitles, Title *wiititles, int wiiuTitlesCount, int vWiiTitlesCount) : wiiutitles(wiiutitles), 11 | wiititles(wiititles), 12 | wiiuTitlesCount(wiiuTitlesCount), 13 | vWiiTitlesCount(vWiiTitlesCount) {} 14 | enum eState { 15 | STATE_MAIN_MENU, 16 | STATE_DO_SUBSTATE, 17 | }; 18 | 19 | enum eSubstateCalled { 20 | NONE, 21 | STATE_BACKUPSET_MENU, 22 | }; 23 | 24 | void render() override; 25 | ApplicationState::eSubState update(Input *input) override; 26 | 27 | private: 28 | std::unique_ptr subState{}; 29 | eState state = STATE_MAIN_MENU; 30 | 31 | eSubstateCalled substateCalled = NONE; 32 | 33 | Title *wiiutitles; 34 | Title *wiititles; 35 | 36 | int wiiuTitlesCount; 37 | int vWiiTitlesCount; 38 | }; -------------------------------------------------------------------------------- /include/menu/TitleOptionsState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class TitleOptionsState : public ApplicationState { 9 | public: 10 | TitleOptionsState(Title title, Task task, int *versionList, int8_t sduser, int8_t wiiuuser, bool common, int8_t wiiuuser_d, Title *titles, int titleCount) : title(title), 11 | task(task), 12 | versionList(versionList), 13 | sduser(sduser), 14 | wiiuuser(wiiuuser), 15 | common(common), 16 | wiiuuser_d(wiiuuser_d), 17 | titles(titles), 18 | titleCount(titleCount) {} 19 | 20 | enum eState { 21 | STATE_TITLE_OPTIONS, 22 | STATE_DO_SUBSTATE, 23 | }; 24 | 25 | enum eSubstateCalled { 26 | NONE, 27 | STATE_BACKUPSET_MENU, 28 | STATE_KEYBOARD 29 | }; 30 | 31 | void render() override; 32 | ApplicationState::eSubState update(Input *input) override; 33 | 34 | private: 35 | std::unique_ptr subState{}; 36 | eState state = STATE_TITLE_OPTIONS; 37 | 38 | eSubstateCalled substateCalled = NONE; 39 | 40 | Title title; 41 | Task task; 42 | 43 | int *versionList; 44 | 45 | int8_t sduser; 46 | int8_t wiiuuser; 47 | bool common; 48 | int8_t wiiuuser_d; 49 | 50 | Title *titles; 51 | int titleCount; 52 | 53 | bool isWiiUTitle; 54 | 55 | uint8_t slot = 0; 56 | int cursorPos = 0; 57 | int entrycount; 58 | 59 | std::string tag; 60 | std::string newTag; 61 | }; -------------------------------------------------------------------------------- /include/menu/TitleTaskState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | class TitleTaskState : public ApplicationState { 9 | public: 10 | TitleTaskState(Title title, Title *titles, int titlesCount) : title(title), 11 | titles(titles), 12 | titlesCount(titlesCount) {} 13 | ~TitleTaskState() { 14 | free(this->versionList); 15 | } 16 | enum eState { 17 | STATE_TITLE_TASKS, 18 | STATE_DO_SUBSTATE, 19 | }; 20 | 21 | void render() override; 22 | ApplicationState::eSubState update(Input *input) override; 23 | 24 | private: 25 | std::unique_ptr subState{}; 26 | eState state = STATE_TITLE_TASKS; 27 | 28 | Title title; 29 | Title *titles; 30 | int titlesCount; 31 | bool isWiiUTitle; 32 | 33 | Task task; 34 | int *versionList = (int *) malloc(0x100 * sizeof(int)); 35 | }; -------------------------------------------------------------------------------- /include/menu/WiiUTitleListState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class WiiUTitleListState : public ApplicationState { 11 | public: 12 | explicit WiiUTitleListState(Title *titles, int titlesCount) : titles(titles), 13 | titlesCount(titlesCount) {} 14 | enum eState { 15 | STATE_WIIU_TITLE_LIST, 16 | STATE_DO_SUBSTATE, 17 | }; 18 | 19 | void render() override; 20 | ApplicationState::eSubState update(Input *input) override; 21 | 22 | private: 23 | std::unique_ptr subState{}; 24 | eState state = STATE_WIIU_TITLE_LIST; 25 | 26 | Title *titles; 27 | 28 | int titlesCount; 29 | 30 | std::vector sortNames = {LanguageUtils::gettext("None"), 31 | LanguageUtils::gettext("Name"), 32 | LanguageUtils::gettext("Storage"), 33 | LanguageUtils::gettext("Storage+Name")}; 34 | 35 | int titleSort = 1; 36 | static int scroll; 37 | static int cursorPos; 38 | bool sortAscending = true; 39 | int targ = 0; 40 | 41 | bool noTitles = false; 42 | }; -------------------------------------------------------------------------------- /include/menu/vWiiTitleListState.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | class vWiiTitleListState : public ApplicationState { 11 | public: 12 | vWiiTitleListState(Title *titles, int titlesCount) : titles(titles), 13 | titlesCount(titlesCount) {} 14 | enum eState { 15 | STATE_VWII_TITLE_LIST, 16 | STATE_DO_SUBSTATE, 17 | }; 18 | 19 | void render() override; 20 | ApplicationState::eSubState update(Input *input) override; 21 | 22 | private: 23 | std::unique_ptr subState{}; 24 | eState state = STATE_VWII_TITLE_LIST; 25 | 26 | Title *titles; 27 | 28 | int titlesCount; 29 | 30 | std::vector sortNames = {LanguageUtils::gettext("None"), 31 | LanguageUtils::gettext("Name"), 32 | LanguageUtils::gettext("Storage"), 33 | LanguageUtils::gettext("Storage+Name")}; 34 | 35 | int titleSort = 1; 36 | static int scroll; 37 | static int cursorPos; 38 | bool sortAscending = true; 39 | int targ = 0; 40 | 41 | bool noTitles = false; 42 | }; -------------------------------------------------------------------------------- /include/savemng.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define __STDC_WANT_LIB_EXT2__ 1 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | 21 | #define PATH_SIZE 0x400 22 | 23 | #define M_OFF 1 24 | #define Y_OFF 1 25 | 26 | enum eBatchRestoreState { 27 | NOT_TRIED = 0, 28 | ABORTED = 1, 29 | OK = 2, 30 | WR = 3, 31 | KO = 4 32 | }; 33 | 34 | struct backupInfo { 35 | bool hasBatchBackup; 36 | bool candidateToBeRestored; 37 | bool candidateToBeBacked; 38 | bool selectedToRestore; 39 | bool selectedToBackup; 40 | bool hasUserSavedata; 41 | bool hasCommonSavedata; 42 | eBatchRestoreState batchRestoreState; 43 | eBatchRestoreState batchBackupState; 44 | int lastErrCode; 45 | }; 46 | 47 | struct Title { 48 | uint32_t highID; 49 | uint32_t lowID; 50 | uint16_t listID; 51 | char shortName[256]; 52 | char longName[512]; 53 | char productCode[5]; 54 | bool saveInit; 55 | bool isTitleOnUSB; 56 | bool isTitleDupe; 57 | bool is_Wii; 58 | bool noFwImg; 59 | uint16_t dupeID; 60 | uint8_t *iconBuf; 61 | uint64_t accountSaveSize; 62 | uint32_t groupID; 63 | backupInfo currentBackup; 64 | }; 65 | 66 | struct Saves { 67 | uint32_t highID; 68 | uint32_t lowID; 69 | uint8_t dev; 70 | bool found; 71 | }; 72 | 73 | struct Account { 74 | char persistentID[9]; 75 | uint32_t pID; 76 | char miiName[50]; 77 | uint8_t slot; 78 | }; 79 | 80 | enum Style { 81 | ST_YES_NO = 1, 82 | ST_CONFIRM_CANCEL = 2, 83 | ST_MULTILINE = 16, 84 | ST_WARNING = 32, 85 | ST_ERROR = 64, 86 | ST_WIPE = 128, 87 | ST_MULTIPLE_CHOICE = 256 88 | }; 89 | 90 | template 91 | void sortTitle(It titles, It last, int tsort = 1, bool sortAscending = true) { 92 | switch (tsort) { 93 | case 0: 94 | std::ranges::sort(titles, last, std::ranges::less{}, &Title::listID); 95 | break; 96 | case 1: { 97 | const auto proj = [](const Title &title) { 98 | return std::string_view(title.shortName); 99 | }; 100 | if (sortAscending) { 101 | std::ranges::sort(titles, last, std::ranges::less{}, proj); 102 | } else { 103 | std::ranges::sort(titles, last, std::ranges::greater{}, proj); 104 | } 105 | break; 106 | } 107 | case 2: 108 | if (sortAscending) { 109 | std::ranges::sort(titles, last, std::ranges::less{}, &Title::isTitleOnUSB); 110 | } else { 111 | std::ranges::sort(titles, last, std::ranges::greater{}, &Title::isTitleOnUSB); 112 | } 113 | break; 114 | case 3: { 115 | const auto proj = [](const Title &title) { 116 | return std::make_tuple(title.isTitleOnUSB, 117 | std::string_view(title.shortName)); 118 | }; 119 | if (sortAscending) { 120 | std::ranges::sort(titles, last, std::ranges::less{}, proj); 121 | } else { 122 | std::ranges::sort(titles, last, std::ranges::greater{}, proj); 123 | } 124 | break; 125 | } 126 | default: 127 | break; 128 | } 129 | } 130 | 131 | bool initFS() __attribute__((__cold__)); 132 | void shutdownFS() __attribute__((__cold__)); 133 | std::string getUSB(); 134 | void consolePrintPos(int x, int y, const char *format, ...) __attribute__((hot)); 135 | bool promptConfirm(Style st, const std::string &question); 136 | void promptError(const char *message, ...); 137 | void promptMessage(Color bgcolor,const char *message, ...); 138 | Button promptMultipleChoice(Style st, const std::string &question); 139 | std::string getDynamicBackupPath(uint32_t highID, uint32_t lowID, uint8_t slot); 140 | std::string getBatchBackupPath(uint32_t highID, uint32_t lowID, uint8_t slot, std::string datetime); 141 | std::string getBatchBackupPathRoot(std::string datetime); 142 | void getAccountsWiiU(); 143 | void getAccountsSD(Title *title, uint8_t slot); 144 | bool hasAccountSave(Title *title, bool inSD, bool iine, uint32_t user, uint8_t slot, int version); 145 | bool getLoadiineGameSaveDir(char *out, const char *productCode, const char *longName, const uint32_t highID, const uint32_t lowID); 146 | bool getLoadiineSaveVersionList(int *out, const char *gamePath); 147 | bool isSlotEmpty(uint32_t highID, uint32_t lowID, uint8_t slot); 148 | bool isSlotEmpty(uint32_t highID, uint32_t lowID, uint8_t slot, const std::string &batchDatetime); 149 | bool folderEmpty(const char *fPath); 150 | bool hasCommonSave(Title *title, bool inSD, bool iine, uint8_t slot, int version); 151 | void copySavedata(Title *title, Title *titled, int8_t wiiuuser, int8_t wiiuuser_d, bool common) __attribute__((hot)); 152 | std::string getNowDateForFolder() __attribute__((hot)); 153 | std::string getNowDate() __attribute__((hot)); 154 | void writeMetadata(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB) __attribute__((hot)); 155 | void writeMetadata(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB,const std::string &batchDatetime) __attribute__((hot)); 156 | void writeMetadataWithTag(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB,const std::string &tag) __attribute__((hot)); 157 | void writeMetadataWithTag(uint32_t highID,uint32_t lowID,uint8_t slot,bool isUSB,const std::string &batchDatetime,const std::string &tag) __attribute__((hot)); 158 | void writeBackupAllMetadata(const std::string & Date, const std::string & tag); 159 | void backupAllSave(Title *titles, int count, const std::string &batchDatetime, bool onlySelectedTitles = false) __attribute__((hot)); 160 | void backupSavedata(Title *title, uint8_t slot, int8_t wiiuuser, bool common, const std::string &tag = "") __attribute__((hot)); 161 | int restoreSavedata(Title *title, uint8_t slot, int8_t sduser, int8_t wiiuuser, bool common, bool interactive = true) __attribute__((hot)); 162 | int wipeSavedata(Title *title, int8_t wiiuuser, bool common, bool interactive = true) __attribute__((hot)); 163 | void importFromLoadiine(Title *title, bool common, int version); 164 | void exportToLoadiine(Title *title, bool common, int version); 165 | int checkEntry(const char *fPath); 166 | bool createFolder(const char *fPath); 167 | int32_t loadFile(const char *fPath, uint8_t **buf) __attribute__((hot)); 168 | int32_t loadTitleIcon(Title *title) __attribute__((hot)); 169 | void consolePrintPosMultiline(int x, int y, const char *format, ...) __attribute__((hot)); 170 | void consolePrintPosAligned(int y, uint16_t offset, uint8_t align, const char *format, ...) __attribute__((hot)); 171 | void kConsolePrintPos(int x, int y, int x_offset, const char *format, ...) __attribute__((hot)); 172 | uint8_t getSDaccn(); 173 | uint8_t getWiiUaccn(); 174 | Account *getWiiUacc(); 175 | Account *getSDacc(); 176 | void deleteSlot(Title *title, uint8_t slot); 177 | bool wipeBackupSet(const std::string &subPath); 178 | void splitStringWithNewLines(const std::string &input, std::string &output); 179 | void sdWriteDisclaimer(); -------------------------------------------------------------------------------- /include/tga_reader.h: -------------------------------------------------------------------------------- 1 | /** 2 | * tga_reader.h 3 | * 4 | * Copyright (c) 2014 Kenji Sasaki 5 | * Released under the MIT license. 6 | * https://github.com/npedotnet/TGAReader/blob/master/LICENSE 7 | * 8 | * English document 9 | * https://github.com/npedotnet/TGAReader/blob/master/README.md 10 | * 11 | * Japanese document 12 | * http://3dtech.jp/wiki/index.php?TGAReader 13 | * 14 | */ 15 | 16 | #pragma once 17 | 18 | #include 19 | #include 20 | 21 | #ifdef __cplusplus 22 | extern "C" { 23 | #endif 24 | 25 | using TGA_ORDER = struct _TGA_ORDER { 26 | int redShift; 27 | int greenShift; 28 | int blueShift; 29 | int alphaShift; 30 | }; 31 | 32 | extern const TGA_ORDER *TGA_READER_ARGB; 33 | extern const TGA_ORDER *TGA_READER_ABGR; 34 | extern const TGA_ORDER *TGA_READER_RGBA; 35 | 36 | void *tgaMalloc(size_t size); 37 | void tgaFree(void *memory); 38 | int tgaGetWidth(const unsigned char *buffer); 39 | int tgaGetHeight(const unsigned char *buffer); 40 | int *tgaRead(const unsigned char *buffer, const TGA_ORDER *order); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif -------------------------------------------------------------------------------- /include/utils/Colors.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define COLOR_WHITE Color(0xffffffff) 4 | #define COLOR_BLACK Color(0, 0, 0, 255) 5 | #define COLOR_BACKGROUND Color(0x00006F00) 6 | #define COLOR_TEXT COLOR_WHITE 7 | #define COLOR_TEXT_AT_CURSOR Color(0xBBBBEEFF) 8 | #define COLOR_LIST_HIGH Color(0x40D070FF) 9 | #define COLOR_LIST_HIGH_AT_CURSOR Color(0x40D0BBFF) 10 | #define COLOR_LIST Color(0x00FF00FF) 11 | #define COLOR_LIST_AT_CURSOR Color(0x00FFAAFF) 12 | #define COLOR_LIST_SKIPPED Color(0x888800FF) 13 | #define COLOR_LIST_SKIPPED_AT_CURSOR Color(0x8888AAFF) 14 | #define COLOR_LIST_SELECTED_NOSAVE Color(0xFFFF00FF) 15 | #define COLOR_LIST_SELECTED_NOSAVE_AT_CURSOR Color(0xCCCC60FF) 16 | #define COLOR_LIST_NOSAVE Color(0xFFFF00FF) 17 | #define COLOR_LIST_NOSAVE_AT_CURSOR Color(0xFFFFBBFF) 18 | #define COLOR_LIST_DANGER Color(0xFF0000FF) 19 | #define COLOR_LIST_DANGER_AT_CURSOR Color(0xFF0060FF) 20 | #define COLOR_LIST_RESTORE_SUCCESS Color(0xFFFFFFFF) 21 | #define COLOR_LIST_RESTORE_SUCCESS_AT_CURSOR Color(0xBBBBEEFF) 22 | #define COLOR_INFO Color(0x88CC88FF) 23 | #define COLOR_INFO_AT_CURSOR Color(0x88CCCCFF) 24 | #define COLOR_CURRENT_BS Color(0xFFBB33FF) 25 | #define COLOR_CURRENT_BS_AT_CURSOR Color(0xFFFF99FF) 26 | #define COLOR_KEY Color(0xFF3333FF) 27 | #define COLOR_KEY_S Color(0xFF666600) 28 | #define COLOR_KEY_C Color(0xFF0000FF) 29 | #define COLOR_BG_SUCCESS Color(0x00DD55FF) 30 | #define COLOR_BG_OK Color(0x00AA0099) 31 | #define COLOR_BG_WR Color(0xBB7F0000) 32 | #define COLOR_BG_KO Color(0x7F000000) 33 | #define COLOR_BG_ERROR Color(0xAA0000FF) 34 | -------------------------------------------------------------------------------- /include/utils/DrawUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "schrift.h" 4 | #include 5 | #include 6 | 7 | // visible screen sizes 8 | #define SCREEN_WIDTH 854 9 | #define SCREEN_HEIGHT 480 10 | 11 | union Color { 12 | explicit Color(uint32_t color) { 13 | this->color = color; 14 | } 15 | 16 | Color(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { 17 | this->r = r; 18 | this->g = g; 19 | this->b = b; 20 | this->a = a; 21 | } 22 | 23 | uint32_t color{}; 24 | struct { 25 | uint8_t r; 26 | uint8_t g; 27 | uint8_t b; 28 | uint8_t a; 29 | }; 30 | }; 31 | 32 | class DrawUtils { 33 | public: 34 | static void setRedraw(bool value); 35 | 36 | static bool getRedraw() { return redraw; } 37 | 38 | static BOOL LogConsoleInit(); 39 | 40 | static void LogConsoleFree(); 41 | 42 | static void beginDraw(); 43 | 44 | static void endDraw(); 45 | 46 | static void clear(Color col); 47 | 48 | static void drawPixel(uint32_t x, uint32_t y, Color col) { drawPixel(x, y, col.r, col.g, col.b, col.a); } 49 | 50 | static void drawPixel(uint32_t x, uint32_t y, uint8_t r, uint8_t g, uint8_t b, uint8_t a); 51 | 52 | static void drawRect(int x1, int y1, int x2, int y2, uint8_t r, uint8_t g, uint8_t b, uint8_t a); 53 | 54 | static bool initFont(); 55 | 56 | static bool setFont(OSSharedDataType fontType); 57 | 58 | static void deinitFont(); 59 | 60 | static void setFontColor(Color col); 61 | static void setFontColorByCursor(Color col, Color colAtCursor,int cursorPos, int line); 62 | 63 | static void print(uint32_t x, uint32_t y, const char *string, bool alignRight = false); 64 | 65 | static void print(uint32_t x, uint32_t y, const wchar_t *string, bool alignRight = false); 66 | 67 | static uint32_t getTextWidth(const char *string); 68 | 69 | static uint32_t getTextWidth(const wchar_t *string); 70 | 71 | static void drawLine(int x1, int y1, int x2, int y2, uint8_t r, uint8_t g, uint8_t b, uint8_t a); 72 | 73 | static void drawPic(int x, int y, uint32_t w, uint32_t h, float scale, const uint32_t *pixels); 74 | 75 | static void drawTGA(int x, int y, float scale, uint8_t *fileContent); 76 | 77 | static void drawRGB5A3(int x, int y, float scale, uint8_t *fileContent); 78 | 79 | static uint32_t initScreen(); 80 | 81 | static uint32_t deinitScreen(); 82 | 83 | static void drawKey(int x,int y,int x_off,Color color); 84 | 85 | 86 | 87 | private: 88 | static bool redraw; 89 | static bool isBackBuffer; 90 | 91 | 92 | static uint8_t *tvBuffer; 93 | static uint8_t *drcBuffer; 94 | 95 | static uint32_t sBufferSizeTV, sBufferSizeDRC; 96 | static BOOL sConsoleHasForeground; 97 | }; 98 | -------------------------------------------------------------------------------- /include/utils/InputUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | typedef enum Button { 8 | PAD_BUTTON_A, 9 | PAD_BUTTON_B, 10 | PAD_BUTTON_X, 11 | PAD_BUTTON_Y, 12 | PAD_BUTTON_UP, 13 | PAD_BUTTON_DOWN, 14 | PAD_BUTTON_LEFT, 15 | PAD_BUTTON_RIGHT, 16 | PAD_BUTTON_L, 17 | PAD_BUTTON_R, 18 | PAD_BUTTON_PLUS, 19 | PAD_BUTTON_MINUS, 20 | PAD_BUTTON_ANY 21 | } Button; 22 | 23 | typedef enum ButtonState { 24 | TRIGGER, 25 | HOLD, 26 | RELEASE 27 | } ButtonState; 28 | 29 | class Input { 30 | public: 31 | void read() __attribute__((hot)); 32 | bool get(ButtonState state, Button button) const __attribute__((hot)); 33 | 34 | private: 35 | VPADStatus vpad_status = {}; 36 | KPADStatus kpad_status = {}; 37 | }; 38 | -------------------------------------------------------------------------------- /include/utils/KeyboardUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | class Keyboard { 8 | public: 9 | friend class KeyboardState; 10 | void render(); 11 | int kbLeft(); 12 | int kbRight(); 13 | int kbUp(); 14 | int kbDown(); 15 | void kbKeyPressed(); 16 | void shiftPressed(); 17 | void delPressed(); 18 | void setCurrentKey(); 19 | std::string getKey(int row_,int column_); 20 | std::string getCurrentKey(); 21 | int getKeyboardRowSize(int row_); 22 | std::string ucs4ToUtf8(const std::u32string& in); 23 | std::u32string utf8ToUcs4(const std::string& in); 24 | std::string input; 25 | Keyboard() : row(2),column(5) { 26 | /* 27 | keysNormal = {"1234567890-= ", 28 | "qwertyuiop[]|", 29 | "asdfghjkl;' ", 30 | "zxcvbnm ,./ "}; 31 | keysShift = { "!@#$%^&*()_+~", 32 | "QWERTYUIOP{}\\", 33 | "ASDFGHJKL:\" ", 34 | "ZXCVBNM <> "}; 35 | */ 36 | std::vector keyboardNormal = { 37 | "KB_N_0", 38 | "KB_N_1", 39 | "KB_N_2", 40 | "KB_N_3" 41 | }; 42 | std::vector keyboardShift = { 43 | "KB_S_0", 44 | "KB_S_1", 45 | "KB_S_2", 46 | "KB_S_3" 47 | 48 | }; 49 | for (unsigned int i=0;i keysNormal; 61 | std::vector keysShift; 62 | std::vector currentKeyboard; 63 | std::u32string currentKey; 64 | int row; 65 | int column; 66 | 67 | }; -------------------------------------------------------------------------------- /include/utils/LanguageUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | typedef enum { 12 | Swkbd_LanguageType__Japanese = 0, 13 | Swkbd_LanguageType__English = 1, 14 | Swkbd_LanguageType__French = 2, 15 | Swkbd_LanguageType__German = 3, 16 | Swkbd_LanguageType__Italian = 4, 17 | Swkbd_LanguageType__Spanish = 5, 18 | Swkbd_LanguageType__Chinese1 = 6, 19 | Swkbd_LanguageType__Korean = 7, 20 | Swkbd_LanguageType__Dutch = 8, 21 | Swkbd_LanguageType__Portuguese = 9, 22 | Swkbd_LanguageType__Russian = 10, 23 | Swkbd_LanguageType__Chinese2 = 11, 24 | Swkbd_LanguageType__Invalid = 12 25 | } Swkbd_LanguageType; 26 | 27 | struct MSG { 28 | uint32_t id; 29 | const char *msgstr; 30 | MSG *next; 31 | }; 32 | 33 | class LanguageUtils { 34 | public: 35 | static void loadLanguage(Swkbd_LanguageType language) __attribute__((cold)); 36 | static std::string getLoadedLanguage(); 37 | static Swkbd_LanguageType getSystemLanguage() __attribute__((cold)); 38 | static Swkbd_LanguageType getSwkbdLoadedLang() { return loadedLang; } __attribute__((cold)); 39 | static void gettextCleanUp() __attribute__((__cold__)); 40 | static const char *gettext(const char *msg) __attribute__((__hot__)); 41 | 42 | private: 43 | static bool gettextLoadLanguage(const char *langFile); 44 | static uint32_t hash_string(const char *str_param); 45 | static MSG *findMSG(uint32_t id); 46 | static void setMSG(const char *msgid, const char *msgstr); 47 | 48 | static MSG *baseMSG; 49 | static Swkbd_LanguageType sysLang; 50 | static Swkbd_LanguageType loadedLang; 51 | 52 | static constexpr uint8_t hashMultiplier = 31; // or 37 53 | }; -------------------------------------------------------------------------------- /include/utils/StateUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class State { 6 | public: 7 | static void init(); 8 | static bool AppRunning(); 9 | static void shutdown(); 10 | static void registerProcUICallbacks(); 11 | static uint32_t ConsoleProcCallbackAcquired(void *context); 12 | static uint32_t ConsoleProcCallbackReleased(void *context); 13 | 14 | private: 15 | static bool aroma; 16 | }; -------------------------------------------------------------------------------- /include/utils/StringUtils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace StringUtils { 10 | bool replace(std::string &str, const std::string &from, const std::string &to); 11 | std::string decodeXMLEscapeLine(std::string xmlString); 12 | template 13 | std::string stringFormat(const std::string &format, Args... args) { 14 | int size_s = std::snprintf(nullptr, 0, format.c_str(), args...) + 1; // Extra space for '\0' 15 | if (size_s <= 0) { throw std::runtime_error("Error during formatting."); } 16 | auto size = static_cast(size_s); 17 | std::unique_ptr buf(new char[size]); 18 | std::snprintf(buf.get(), size, format.c_str(), args...); 19 | return std::string(buf.get(), buf.get() + size - 1); // We don't want the '\0' inside 20 | } 21 | }; // namespace StringUtils -------------------------------------------------------------------------------- /include/utils/schrift.h: -------------------------------------------------------------------------------- 1 | /* This file is part of libschrift. 2 | * 3 | * © 2019-2022 Thomas Oltmann and contributors 4 | * 5 | * Permission to use, copy, modify, and/or distribute this software for any 6 | * purpose with or without fee is hereby granted, provided that the above 7 | * copyright notice and this permission notice appear in all copies. 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ 16 | 17 | #ifndef SCHRIFT_H 18 | #define SCHRIFT_H 1 19 | 20 | #include /* size_t */ 21 | #include /* uint_fast32_t, uint_least32_t */ 22 | 23 | #ifdef __cplusplus 24 | extern "C" { 25 | #endif 26 | 27 | #define SFT_DOWNWARD_Y 0x01 28 | 29 | typedef struct SFT SFT; 30 | typedef struct SFT_Font SFT_Font; 31 | typedef uint_least32_t SFT_UChar; /* Guaranteed to be compatible with char32_t. */ 32 | typedef uint_fast32_t SFT_Glyph; 33 | typedef struct SFT_LMetrics SFT_LMetrics; 34 | typedef struct SFT_GMetrics SFT_GMetrics; 35 | typedef struct SFT_Kerning SFT_Kerning; 36 | typedef struct SFT_Image SFT_Image; 37 | 38 | struct SFT { 39 | SFT_Font *font; 40 | double xScale; 41 | double yScale; 42 | double xOffset; 43 | double yOffset; 44 | int flags; 45 | }; 46 | 47 | struct SFT_LMetrics { 48 | double ascender; 49 | double descender; 50 | double lineGap; 51 | }; 52 | 53 | struct SFT_GMetrics { 54 | double advanceWidth; 55 | double leftSideBearing; 56 | int yOffset; 57 | int minWidth; 58 | int minHeight; 59 | }; 60 | 61 | struct SFT_Kerning { 62 | double xShift; 63 | double yShift; 64 | }; 65 | 66 | struct SFT_Image { 67 | void *pixels; 68 | int width; 69 | int height; 70 | }; 71 | 72 | const char *sft_version(void); 73 | 74 | SFT_Font *sft_loadmem(const void *mem, size_t size); 75 | void sft_freefont(SFT_Font *font); 76 | 77 | int sft_lmetrics(const SFT *sft, SFT_LMetrics *metrics); 78 | int sft_lookup(const SFT *sft, SFT_UChar codepoint, SFT_Glyph *glyph); 79 | int sft_gmetrics(const SFT *sft, SFT_Glyph glyph, SFT_GMetrics *metrics); 80 | int sft_kerning(const SFT *sft, SFT_Glyph leftGlyph, SFT_Glyph rightGlyph, 81 | SFT_Kerning *kerning); 82 | int sft_render(const SFT *sft, SFT_Glyph glyph, SFT_Image image); 83 | 84 | #ifdef __cplusplus 85 | } 86 | #endif 87 | 88 | #endif 89 | -------------------------------------------------------------------------------- /include/version.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define VERSION_MAJOR 1 4 | #define VERSION_MINOR 6 5 | #define VERSION_MICRO 5 6 | #define VERSION_FIX 'i' 7 | -------------------------------------------------------------------------------- /meta/hbl/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpl0itU/savemii/184e9aed89d416aaebd2d8fc4e3621100b81466c/meta/hbl/icon.png -------------------------------------------------------------------------------- /meta/hbl/meta.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | SaveMii WUT 4 | DaThinkingChair,w3irDv 5 | 1.6.5i 6 | 202501190000 7 | WiiU/vWii Save Manager 8 | WiiU/vWii Save Manager 9 | 10 | This homebrew allows you to backup your Wii U and vWii savegames to the SD card and also restore them. Can also 11 | copy saves from NAND<->USB if title is installed to both. Up to 256 backups can be made per title. Backups are 12 | stored in sd:/wiiu/backups. 13 | 14 | tool 15 | https://github.com/Xpl0itU/savemii/releases 16 | 17 | -------------------------------------------------------------------------------- /meta/wuhb/drc-splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpl0itU/savemii/184e9aed89d416aaebd2d8fc4e3621100b81466c/meta/wuhb/drc-splash.png -------------------------------------------------------------------------------- /meta/wuhb/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpl0itU/savemii/184e9aed89d416aaebd2d8fc4e3621100b81466c/meta/wuhb/icon.png -------------------------------------------------------------------------------- /meta/wuhb/tv-splash.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Xpl0itU/savemii/184e9aed89d416aaebd2d8fc4e3621100b81466c/meta/wuhb/tv-splash.png -------------------------------------------------------------------------------- /romfs/languages/SChinese.json: -------------------------------------------------------------------------------- 1 | { 2 | "Disclaimer:": "注意:", 3 | "There is always the potential for a brick.": "请尽量小心使用此程序,它可能会导致砖机。", 4 | "Everything you do with this software is your own responsibility": "你所使用此程序做的一切都是你自己的责任", 5 | "Out of memory.": "内存不足", 6 | "Loaded %i Wii U titles.": "已加载 %i 个Wii U软件。", 7 | "%s%s (No banner.bin)": "%s%s(没有banner.bin数据)", 8 | "Loaded %i Wii titles.": "已加载 %i 个Wii软件", 9 | "None": "无", 10 | "Name": "名称", 11 | "Storage": "存储设备", 12 | "Storage+Name": "存储设备+名称", 13 | "initFS failed. Please make sure your MochaPayload is up-to-date": "初始化文件系统失败。\n请确保你正在使用最新版MochaPayload", 14 | " Wii U Save Management (%u Title%s)": " Wii U保存数据管理(%u 软件)", 15 | " vWii Save Management (%u Title%s)": " vWii保存数据管理(%u 软件)", 16 | " Batch Backup": " 批量备份", 17 | "\uE002: Options \ue000: Select Mode": "\uE002:选项 \ue000:选择模式", 18 | " Backup All (%u Title%s)": " 备份所有保存数据(%u 软件)", 19 | " Backup Wii U (%u Title%s)": " 备份Wii U软件的保存数据(%u 软件)", 20 | " Backup vWii (%u Title%s)": " 备份vWii软件的保存数据(%u 软件)", 21 | "\ue000: Backup \ue001: Back": "\ue000:备份 \ue001:返回", 22 | "%s Sort: %s \ue084": "%s 排序方式: %s \ue084", 23 | " [Not Init]": "[未初始化]", 24 | "\ue000: Select Game \ue001: Back": "\ue000:选择游戏 \ue001:返回", 25 | " Backup savedata": " 备份保存数据", 26 | " Restore savedata": " 还原保存数据", 27 | " Wipe savedata": " 清除保存数据", 28 | " Import from loadiine": " 从loadiine导入", 29 | " Export to loadiine": " 导出到loadiine", 30 | " Copy Savedata to Title in %s": "将保存数据复制到 %s 软件", 31 | "\ue000: Select Task \ue001: Back": "\ue000:选择 \ue001:返回", 32 | "Destination:": "目标位置:", 33 | "Select %s:": "选择 %s:", 34 | "version": "Ver", 35 | "Delete from:": "从删除:", 36 | "slot": "保存数据槽位", 37 | "Empty": "无数据", 38 | "Used": "已使用", 39 | "Select SD user to copy from:": "选择从SD复制数据的用户:", 40 | "all users": "所有用户", 41 | "Has Save": "该用户有保存数据", 42 | "Select Wii U user to delete from:": "选择从SD删除数据的用户:", 43 | "Select Wii U user%s:": "选择Wii U的用户%s:", 44 | " to copy from": "从", 45 | " to copy to": "复制到", 46 | "Date: %s": "保存日期:%s", 47 | "Include 'common' save?": "包括common保存数据一起吗?", 48 | "yes": "是", 49 | "no ": "不", 50 | "No 'common' save found.": "没有发现common保存数据", 51 | "\ue000: Wipe \ue001: Back": "\ue000:删除 \ue001:返回", 52 | "\ue000: Import \ue001: Back": "\ue000:导入 \ue001:返回", 53 | "\ue000: Export \ue001: Back": "\ue000:导出 \ue001:返回", 54 | "\ue000: Copy \ue001: Back": "\ue000:复制 \ue001:返回", 55 | "Press \ue044 to exit.": "按下 \ue044 退出程序。", 56 | "No Wii U titles found.": "未发现Wii U软件", 57 | "No vWii saves found.": "未发现vWii保存数据", 58 | "CBHC save. Could be dangerous to modify. Continue?": "这是CBHC的保存数据。修改它可能会导致一些问题,继续吗?", 59 | "Are you REALLY sure?": "你真的真的要这样做吗??", 60 | "vWii saves are in the vWii section. Continue?": "vWii的保存数据在vWii的存储中。继续?", 61 | "Recommended to run Game at least one time. Continue?": "请至少运行一次软件。继续?", 62 | "No save to Backup.": "没有可备份的保存数据", 63 | "No save to Wipe.": "没有可删除的保存数据", 64 | "No save to Export.": "没有可导出的保存数据", 65 | "No save to Copy.": "没有可以复制的保存数据", 66 | "Copying file: %s": "正在复制文件 %s", 67 | "From: %s": "从 %s", 68 | "To: %s": "到 %s", 69 | "\ue000 Yes - \ue001 No": "\ue000 是 - \ue001 否", 70 | "\ue000 Confirm - \ue001 Cancel": "\ue000 确认 - \ue001 取消", 71 | "Filesize: %d bytes": "文件大小:%d 字节", 72 | "Deleting folder %s": "正在删除 %s 文件夹", 73 | "From: \n%s": "从:\n%s", 74 | "Failed to delete folder\n\n%s\n%s": "删除文件夹失败\n\n%s\n%s", 75 | "Deleting file %s": "正在删除文件 %s", 76 | "Failed to delete file\n\n%s\n%s": "删除文件失败\n\n%s\n%s", 77 | "Loadiine game folder not found.": "没有发现Loadiine游戏文件夹。", 78 | "Failed to open Loadiine game save directory.": "Loadiine游戏文件夹无法打开。", 79 | "Are you sure?": "你确定吗?", 80 | "Backup current savedata first to next empty slot?": "是否在下一个槽位中备份当前的保存数据?", 81 | "Backup done. Now copying Savedata.": "备份完成。现在复制保存数据。", 82 | "Common save not found.": "没有发现common保存数据", 83 | "Copy failed.": "复制保存数据失败。", 84 | "%s\nBackup failed.": "%s\n备份保存数据失败。", 85 | "Backup found on this slot. Overwrite it?": "这个槽位有保存数据,覆盖吗?", 86 | "No save found for this user.": "这个用户没有保存数据。", 87 | "%s\nBackup failed. DO NOT restore from this slot.": "备份保存数据失败。此槽位的保存数据不要还原!", 88 | "No backup found on selected slot.": "没有在选择的槽位发现保存数据。", 89 | "Restore failed.": "还原保存数据失败。", 90 | "Hm, are you REALLY sure?": "你真的真的要这样做吗??", 91 | "Backup current savedata first?": "要不要先备份现在的保存数据?", 92 | "Failed to import savedata from loadiine.": "导入loadiine保存数据失败。", 93 | "Failed to export savedata to loadiine.": "导出保存数据到loadiine失败。", 94 | "\ue083 Sort: %s \ue084": "\ue083 排序方式: %s \ue084", 95 | "\ue000: Select BackupSet \ue001: Back": "\ue000: 选择存档集 \ue001: 返回", 96 | "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: 更改存档集 \ue000: 还原 \ue001: 返回", 97 | "WiiU USB Savedata >> slot 0": "WiiU USB保存数据 >> slot 0", 98 | "WiiU NAND Savedata >> slot 1": "WiiU NAND保存数据 >> slot 1", 99 | "vWii Savedata >> slot 0": "vWii保存数据 >> slot 0", 100 | "BackupSet: %s": "存档集: %s", 101 | ", from ": ",来自", 102 | "Common save not restored.": "Common数据还原失败。", 103 | "\ue001: Back": "\ue001: 返回", 104 | "Failed to delete slot %u.": "无法删除槽位%u。", 105 | "Error setting path. Aborting.": "错误的路径设置!已取消操作。", 106 | "Failed to delete backupSet %s.": "无法删除存档集%s。", 107 | "\ue000: Backup \ue046 Delete Slot \ue001: Back": "\ue000: 备份 \ue046 删除槽位 \ue001: 返回", 108 | "\ue003 Confirm - \ue001 Cancel": "\ue003 确认 - \ue001 取消", 109 | "Wipe BackupSet - Are you sure?": "删除存档集 - 是否继续?", 110 | "Wipe BackupSet - Hm, are you REALLY sure?": "删除存档集 - 你真的真的要这样做吗??", 111 | "Initializing BackupSets metadata.": "初始化存档集数据。", 112 | "Filter BackupSets": "存档集过滤器", 113 | "Show only BackupSets satisfying all these conditions:": "仅显示满足以下所有条件的存档集:", 114 | "Console: %s": "主机: %s", 115 | "Tag: %s": "标记: %s", 116 | "Month: %s": "月份: %s", 117 | "Year: %s": "年份: %s", 118 | "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000:应用过滤器 \uE002:重置过滤器 \ue001:返回", 119 | "BackupSets": "存档集", 120 | "BackupSets (filter applied)": "存档集(过滤器已启用)", 121 | "\ue000: Select BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: 选择存档集 \ue046:删除存档集 \ue003:过滤器 \ue001:返回", 122 | "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", 123 | "Batch Backup": "批量备份", 124 | "Backup": "备份", 125 | "Restore": "还原", 126 | "Wipe": "删除", 127 | "Import Loadiine": "从loadiine导入", 128 | "Export Loadiine": "导出到Loadiine", 129 | "Copy to Other Device": "复制到其它存储设备", 130 | "Tasks": "选择选项", 131 | " Batch Restore": " 批量还原", 132 | " Language: %s": " 当前语言:%s", 133 | " Restore Wii U (%u Title%s)": " 还原Wii U(%u 软件)", 134 | " Restore vWii (%u Title%s)": " 还原vWii(%u 软件)", 135 | " [vWiiInject]": " [vWii注入]", 136 | "%s \n Common save not found.": "%s \n未发现Common保存数据。", 137 | "%s \n Failed to delete common folder:\n%s\n%s": "%s \n删除common文件夹失败:\n%s\n%s", 138 | "%s \n Failed to delete savefile:\n%s": "%s \n删除保存文件失败:\n%s", 139 | "%s \n Failed to delete user folder:\n%s\n%s": "%s \n删除用户文件夹失败:\n%s\n%s", 140 | "%s\nCommon save not restored.": "%s\nCommon保存数据未被还原。", 141 | "%s\nNo backup found on selected slot.": "%s\n在已选槽位没有发现备份数据。", 142 | "%s\nNo save found for this user.": "%s\n未发现这个用户的保存数据。", 143 | "%s\nRestore failed.": "%s\n还原失败。", 144 | "- Include common savedata: N": "- 包含common保存数据:N", 145 | "- Perform full backup: N": "- 执行完全备份:N", 146 | "- Restore allusers": "- 还原所有用户", 147 | "- Restore from %s to < %s (%s) >": "- 从 %s 还原到 < %s (%s) >", 148 | "- Wipe data: N": "- 删除数据:N", 149 | ">> Skip": ">> 跳过", 150 | "Any Button: Back": "按任意键返回", 151 | "Batch Restore - Select & Go": "批量还原 - 选择并开始", 152 | "Batch Restore allows you to restore all savedata from a BatchBackup \n* to a different user in the same console \n* or to a different console where the games are previouly installed.\nIn the later case, it is recommended to first run the game to \n initialize the savedata.": "批量还原将会把批量备份中的所有保存数据\n还原到同一主机上的其他用户或先前安装游戏的其他主机。\n\n在后一种情况下,\n建议先运行游戏以初始化保存数据。", 153 | "Batch Restore": "批量还原", 154 | "BatchRestore - Options": "批量还原 - 选项", 155 | "Configuration Options": "设置", 156 | "English": "English", 157 | "Folder does not exist.": "文件夹不存在。", 158 | "German": "German", 159 | "Getting Serial ID": "获取序列号", 160 | "Initializing ROMFS": "初始化ROMFS", 161 | "Initializing WPAD and KAPD": "初始化WPAD与KAPD", 162 | "Initializing loadWiiU Titles": "初始化loadWiiU Titles", 163 | "Italian": "Italian", 164 | "Japanese": "Japanese", 165 | "Keyboard": "键盘", 166 | "Korean": "Korean", 167 | "Main menu": "主菜单", 168 | "No Wii U titles found": "未发现Wii U软件", 169 | "No titles found": "未发现已安装软件", 170 | "No vWii titles found.": "未发现vWii软件。", 171 | "No": "不", 172 | "Portuguese": "Portuguese", 173 | "Press \ue000 to continue": "按\ue000继续", 174 | "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "还原完成。结果:\n-完成:%d\n-警告:%d\n-删除:%d\n-已拒绝:%d\n-已跳过:%d\n", 175 | "Root BackupSet cannot be selected for batchRestore": "Root存档集不适用于批量还原", 176 | "Russian": "Russian", 177 | "Select Wii U user to copy to": "选择目标Wii U用户", 178 | "Simplified Chinese": "简体中文", 179 | "Spanish": "Spanish", 180 | "Strg+Nm": "Strg+Nm", 181 | "There are no titles matching selected filters.": "没有匹配过滤器的结果", 182 | "Traditional Chinese": "繁体中文", 183 | "Wii U Titles": "Wii U软件", 184 | "WiiU Serial Id: %s": "WiiU序列号:%s", 185 | "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "已选:\n%s\n%s。\n是否继续?\n\n", 186 | "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "已设置以下选项:\n%s\n%s\n%s\n%s。\n是否继续?\n\n", 187 | "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "你选择了未初始化的软件(非必要)。\n你百分百确定要这样做吗?", 188 | "[AB]": "[AB]", 189 | "[KO]": "[KO]", 190 | "[OK]": "[OK]", 191 | "[WR]": "[WR]", 192 | "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000:备份 \ue045:标记槽位 \ue046:删除槽位 \ue001:返回", 193 | "\ue000: Continue to batch restore \ue001: Back": "\ue000:继续批量还原 \ue001:返回", 194 | "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000:完成!打开软件选择 \ue001:返回", 195 | "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000:输入 \uE003: Shift \uE002:退格 \ue045:结束 \ue001:返回", 196 | "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000:选择存档集 \ue045:标记存档集 \ue046:删除存档集 \ue003:过滤器 \ue001:返回", 197 | "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e:选择/取消选择 \ue000:还原所选应用 \ue001:返回", 198 | "same user than in source": "与备份数据的目标用户相同", 199 | "vWii Titles": "vWii软件", 200 | "|Restored|": "|已还原|", 201 | " BackupSet Management": " 存档集管理", 202 | "BS: %s": "存档集:%s", 203 | "pre-BatchRestore Backup (WiiU)": "预批量还原备份(WiiU)", 204 | "pre-BatchRestore Backup (vWii)": "预批量还原备份(vWii)", 205 | "pre-Restore backup": "预还原备份", 206 | "pre-Wipe backup": "预删除备份", 207 | "pre-copyToOtherDev backup": "预复制到其它设备备份", 208 | "UNUSABLE SLOT - BACKUP FAILED": "无法使用的槽位!备份失败!", 209 | "Cannot open file for read\n\n%s\n%s": "无法打开文件进行读取\n\n%s\n%s", 210 | "Cannot open file for write\n\n%s\n%s": "无法打开文件进行写入\n\n%s\n%s", 211 | "Error opening source dir\n\n%s\n%s": "打开源目录出错\n\n%s\n%s", 212 | "Read error\n%s": "读取错误\n%s", 213 | "Write error\n%s": "写入错误\n%s", 214 | "\ue002: Change BackupSet \ue000: Restore \ue045 Tag Slot \ue001: Back": "\ue002:更改存档集 \ue000:还原 \ue045:标记槽位 \ue001:返回", 215 | "Error while creating final folder:\n\n%s\n%lx": "创建最终文件夹时出错:\n\n%s\n%lx", 216 | "Error while creating folder:\n\n%s\n%lx": "创建文件夹时出错:\n\n%s\n%lx", 217 | "Error while creating folder:\n\n%s\n%s": "创建文件夹时出错:\n\n%s\n%s", 218 | "Initializing FS": "初始化FS", 219 | "Please wait. First write to (some) SDs can take several seconds.": "请稍候。首次写入SD卡可能需要几秒钟。", 220 | "KB_N_0": "1234567890-=", 221 | "KB_N_1": "qwertyuiop[]|", 222 | "KB_N_2": "asdfghjkl;'", 223 | "KB_N_3": "zxcvbnm ,./", 224 | "KB_S_0": "!@#$%^&*()_+~", 225 | "KB_S_1": "QWERTYUIOP{}\\", 226 | "KB_S_2": "ASDFGHJKL:\"", 227 | "KB_S_3": "ZXCVBNM <>" 228 | } -------------------------------------------------------------------------------- /romfs/languages/TChinese.json: -------------------------------------------------------------------------------- 1 | { 2 | "Disclaimer:": "注意:", 3 | "There is always the potential for a brick.": "請盡量小心使用本程式,它可能會使你的機器變磚。", 4 | "Everything you do with this software is your own responsibility": "你所使用本程式所做的一切都是你自己的責任", 5 | "Out of memory.": "記憶體不足。", 6 | "Loaded %i Wii U titles.": "已加載 %i 個Wii U軟體。", 7 | "%s%s (No banner.bin)": "%s%s(沒有banner.bin資料)", 8 | "Loaded %i Wii titles.": "已加載 %i 個Wii軟體。", 9 | "None": "無", 10 | "Name": "名稱", 11 | "Storage": "存儲", 12 | "Storage+Name": "存儲+名稱", 13 | "initFS failed. Please make sure your MochaPayload is up-to-date": "初始化資料系統失敗。請確保MochaPayload是最新。", 14 | " Wii U Save Management (%u Title%s)": " Wii U保存資料管理(%u 軟體)", 15 | " vWii Save Management (%u Title%s)": " vWii保存資料管理(%u 軟體)", 16 | " Batch Backup": " 批量備份", 17 | "\uE002: Options \ue000: Select Mode": "\uE002:選項 \ue000:選擇模式", 18 | " Backup All (%u Title%s)": " 全部備份(%u 軟體)", 19 | " Backup Wii U (%u Title%s)": " 備份Wii U軟體(%u 軟體)", 20 | " Backup vWii (%u Title%s)": " 備份vWii軟體(%u 軟體)", 21 | "\ue000: Backup \ue001: Back": "\ue000:備份 \ue001:返回", 22 | "%s Sort: %s \ue084": "%s 排序:%s \ue084", 23 | " [Not Init]": "[未初始化]", 24 | "\ue000: Select Game \ue001: Back": "\ue000:選擇遊戲 \ue001:返回", 25 | " Backup savedata": " 備份保存數據", 26 | " Restore savedata": " 恢復保存數據", 27 | " Wipe savedata": " 刪除保存數據", 28 | " Import from loadiine": " 從loadiine導入", 29 | " Export to loadiine": " 導出到loadiine", 30 | " Copy Savedata to Title in %s": " 將Savedata複製到軟體 %s 中。", 31 | "\ue000: Select Task \ue001: Back": "\ue000:選擇任務 \ue001:返回", 32 | "Destination:": "目標定位:", 33 | "Select %s:": "選擇 %s:", 34 | "version": "Ver", 35 | "Delete from:": "刪除:", 36 | "slot": "資料槽位", 37 | "Empty": "空", 38 | "Used": "被使用", 39 | "Select SD user to copy from:": "選擇從SD復制資料的使用者:", 40 | "all users": "所有使用者", 41 | "Has Save": "该使用者有保存資料", 42 | "Select Wii U user to delete from:": "选择从SD删除数据的用户:", 43 | "Select Wii U user%s:": "選擇Wii U使用者:", 44 | " to copy from": " ", 45 | " to copy to": " ", 46 | "Date: %s": "資料導出日期:%s", 47 | "Include 'common' save?": "包括'common'保存資料?", 48 | "yes": "是", 49 | "no ": "不", 50 | "No 'common' save found.": "未找到'common'保存資料。", 51 | "\ue000: Wipe \ue001: Back": "\ue000:刪除 \ue001:返回", 52 | "\ue000: Import \ue001: Back": "\ue000:導入 \ue001:返回", 53 | "\ue000: Export \ue001: Back": "\ue000:導出 \ue001:返回", 54 | "\ue000: Copy \ue001: Back": "\ue000:複製 \ue001:返回", 55 | "Press \ue044 to exit.": "按 \ue044 退出程式。", 56 | "No Wii U titles found.": "未找到Wii U軟體。", 57 | "No vWii saves found.": "未找到vWii保存資料。", 58 | "CBHC save. Could be dangerous to modify. Continue?": "此爲CBHC保存資料。修改可能很危險。繼續?", 59 | "Are you REALLY sure?": "你真的確定嗎?", 60 | "vWii saves are in the vWii section. Continue?": "vWii保存資料在vWii中。繼續?", 61 | "Recommended to run Game at least one time. Continue?": "請至少運行一次軟體。繼續?", 62 | "No save to Backup.": "沒有保存資料可以備份。", 63 | "No save to Wipe.": "沒有保存資料可以刪除。", 64 | "No save to Export.": "沒有保存資料可以導出。", 65 | "No save to Copy.": "沒有保存資料可以復制。", 66 | "Copying file: %s": "複製資料: %s", 67 | "From: %s": "從:%s", 68 | "To: %s": "到:%s", 69 | "\ue000 Yes - \ue001 No": "\ue000 是 - \ue001 否", 70 | "\ue000 Confirm - \ue001 Cancel": "\ue000 確認 - \ue001 取消", 71 | "Filesize: %d bytes": "資料大小:%d 個字節", 72 | "Deleting folder %s": "刪除資料夾 %s", 73 | "From: \n%s": "從:\n%s", 74 | "Failed to delete folder\n\n%s\n%s": "無法刪除資料夾\n\n%s\n%s", 75 | "Deleting file %s": "刪除資料 %s", 76 | "Failed to delete file\n\n%s\n%s": "無法刪除資料\n\n%s\n%s", 77 | "Loadiine game folder not found.": "未找到Loadiine遊戲資料夾。", 78 | "Failed to open Loadiine game save directory.": "打開Loadiine遊戲保存資料夾失敗。", 79 | "Are you sure?": "你確定嗎?", 80 | "Backup current savedata first to next empty slot?": "首先將當前保存數據備份到下一個空插槽?", 81 | "Backup done. Now copying Savedata.": "備份完成。現在復制Savedata。", 82 | "Common save not found.": "Common保存資料未找到。", 83 | "Copy failed.": "複製失敗。", 84 | "%s\nBackup failed.": "%s\n備份失敗。", 85 | "Backup found on this slot. Overwrite it?": "在此槽位上找到備份。覆蓋?", 86 | "No save found for this user.": "未找到此使用者的保存資料。", 87 | "%s\nBackup failed. DO NOT restore from this slot.": "%s\n備份失敗。請不要從該槽位恢復。", 88 | "No backup found on selected slot.": "在選定的槽位上找不到備份。", 89 | "Restore failed.": "還原失敗。", 90 | "Hm, are you REALLY sure?": "蛤?你真的確定嗎?", 91 | "Backup current savedata first?": "先備份當前的保存數據?", 92 | "Failed to import savedata from loadiine.": "导入loadiine保存数据失败。", 93 | "Failed to export savedata to loadiine.": "导出保存数据到loadiine失败。", 94 | "\ue083 Sort: %s \ue084": "\ue083 排序方式: %s \ue084", 95 | "\ue000: Select BackupSet \ue001: Back": "\ue000: 选择存檔集 \ue001: 返回", 96 | "\ue002: Change BackupSet \ue000: Restore \ue001: Back": "\ue002: 更改存檔集 \ue000: 还原 \ue001: 返回", 97 | "WiiU USB Savedata >> slot 0": "WiiU USB保存数据 >> slot 0", 98 | "WiiU NAND Savedata >> slot 1": "WiiU NAND保存数据 >> slot 1", 99 | "vWii Savedata >> slot 0": "vWii保存数据 >> slot 0", 100 | "BackupSet: %s": "存檔集: %s", 101 | ", from ": ",来自", 102 | "Common save not restored.": "Common数据还原失败。", 103 | "\ue001: Back": "\ue001: 返回", 104 | "Failed to delete slot %u.": "无法删除槽位%u。", 105 | "Error setting path. Aborting.": "错误的路径设置!已取消操作。", 106 | "Failed to delete backupSet %s.": "无法删除存檔集%s。", 107 | "\ue000: Backup \ue046 Delete Slot \ue001: Back": "\ue000: 备份 \ue046 删除槽位 \ue001: 返回", 108 | "\ue003 Confirm - \ue001 Cancel": "\ue003 确认 - \ue001 取消", 109 | "Wipe BackupSet - Are you sure?": "删除存檔集 - 是否继续?", 110 | "Wipe BackupSet - Hm, are you REALLY sure?": "删除存檔集 - 你真的真的要这样做吗??", 111 | "Initializing BackupSets metadata.": "初始化存檔集数据。", 112 | "Filter BackupSets": "存檔集过滤器", 113 | "Show only BackupSets satisfying all these conditions:": "仅显示满足以下所有条件的存檔集:", 114 | "Console: %s": "主机: %s", 115 | "Tag: %s": "标记: %s", 116 | "Month: %s": "月份: %s", 117 | "Year: %s": "年份: %s", 118 | "\ue000: Apply Filter \uE002: Reset Filters \ue001: Back": "\ue000:应用过滤器 \uE002:重置过滤器 \ue001:返回", 119 | "BackupSets": "存檔集", 120 | "BackupSets (filter applied)": "存檔集(过滤器已启用)", 121 | "\ue000: Select BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000: 选择存檔集 \ue046:删除存檔集 \ue003:过滤器 \ue001:返回", 122 | "\ue000: Select BackupSet \ue003: Filter List \ue001: Back": "\ue000: Select BackupSet \ue003: Filter List \ue001: Back", 123 | "Batch Backup": "批量备份", 124 | "Backup": "备份", 125 | "Restore": "还原", 126 | "Wipe": "删除", 127 | "Import Loadiine": "从loadiine导入", 128 | "Export Loadiine": "导出到Loadiine", 129 | "Copy to Other Device": "复制到其它存储设备", 130 | "Tasks": "进程", 131 | " Batch Restore": " 批量还原", 132 | " Language: %s": " 当前语言:%s", 133 | " Restore Wii U (%u Title%s)": " 还原Wii U(%u 软件)", 134 | " Restore vWii (%u Title%s)": " 还原vWii(%u 软件)", 135 | " [vWiiInject]": " [vWii注入]", 136 | "%s \n Common save not found.": "%s \n未发现Common保存数据。", 137 | "%s \n Failed to delete common folder:\n%s\n%s": "%s \n删除common文件夹失败:\n%s\n%s", 138 | "%s \n Failed to delete savefile:\n%s": "%s \n删除保存文件失败:\n%s", 139 | "%s \n Failed to delete user folder:\n%s\n%s": "%s \n删除用户文件夹失败:\n%s\n%s", 140 | "%s\nCommon save not restored.": "%s\nCommon保存数据未被还原。", 141 | "%s\nNo backup found on selected slot.": "%s\n在已选槽位没有发现备份数据。", 142 | "%s\nNo save found for this user.": "%s\n未发现这个用户的保存数据。", 143 | "%s\nRestore failed.": "%s\n还原失败。", 144 | "- Include common savedata: N": "- 包含common保存数据:N", 145 | "- Perform full backup: N": "- 执行完全备份:N", 146 | "- Restore allusers": "- 还原所有用户", 147 | "- Restore from %s to < %s (%s) >": "- 从 %s 还原到 < %s (%s) >", 148 | "- Wipe data: N": "- 删除数据:N", 149 | ">> Skip": ">> 跳过", 150 | "Any Button: Back": "按任意键返回", 151 | "Batch Restore - Select & Go": "批量还原 - 选择并开始", 152 | "Batch Restore allows you to restore all savedata from a BatchBackup \n* to a different user in the same console \n* or to a different console where the games are previouly installed.\nIn the later case, it is recommended to first run the game to \n initialize the savedata.": "批量还原将会把批量备份中的所有保存数据\n还原到同一主机上的其他用户或先前安装游戏的其他主机。\n\n在后一种情况下,\n建议先运行游戏以初始化保存数据。", 153 | "Batch Restore": "批量还原", 154 | "BatchRestore - Options": "批量还原 - 选项", 155 | "Configuration Options": "设置", 156 | "English": "English", 157 | "Folder does not exist.": "文件夹不存在。", 158 | "German": "German", 159 | "Getting Serial ID": "获取序列号", 160 | "Initializing ROMFS": "初始化ROMFS", 161 | "Initializing WPAD and KAPD": "初始化WPAD与KAPD", 162 | "Initializing loadWiiU Titles": "初始化loadWiiU Titles", 163 | "Italian": "Italian", 164 | "Japanese": "Japanese", 165 | "Keyboard": "键盘", 166 | "Korean": "Korean", 167 | "Main menu": "主菜单", 168 | "No Wii U titles found": "未发现Wii U软件", 169 | "No titles found": "未发现已安装软件", 170 | "No vWii titles found.": "未发现vWii软件。", 171 | "No": "不", 172 | "Portuguese": "Portuguese", 173 | "Press \ue000 to continue": "按\ue000继续", 174 | "Restore completed. Results:\n- OK: %d\n- Warning: %d\n- KO: %d\n- Aborted: %d\n- Skipped: %d\n": "还原完成。结果:\n-完成:%d\n-警告:%d\n-删除:%d\n-已拒绝:%d\n-已跳过:%d\n", 175 | "Root BackupSet cannot be selected for batchRestore": "Root存檔集不适用于批量还原", 176 | "Russian": "Russian", 177 | "Select Wii U user to copy to": "选择目标Wii U用户", 178 | "Simplified Chinese": "简体中文", 179 | "Spanish": "Spanish", 180 | "Strg+Nm": "Strg+Nm", 181 | "There are no titles matching selected filters.": "没有匹配过滤器的结果", 182 | "Traditional Chinese": "繁体中文", 183 | "Wii U Titles": "Wii U软件", 184 | "WiiU Serial Id: %s": "WiiU序列号:%s", 185 | "You have selected the following options:\n%s\n%s.\nContinue?\n\n": "已选:\n%s\n%s。\n是否继续?\n\n", 186 | "You have selected the following options:\n%s\n%s\n%s\n%s.\nContinue?\n\n": "已设置以下选项:\n%s\n%s\n%s\n%s。\n是否继续?\n\n", 187 | "You have selected uninitialized titles (not recommended). Are you 100%% sure?": "你选择了未初始化的软件(非必要)。\n你百分百确定要这样做吗?", 188 | "[AB]": "[AB]", 189 | "[KO]": "[KO]", 190 | "[OK]": "[OK]", 191 | "[WR]": "[WR]", 192 | "\ue000: Backup \ue045 Tag Slot \ue046 Delete Slot \ue001: Back": "\ue000:备份 \ue045:标记槽位 \ue046:删除槽位 \ue001:返回", 193 | "\ue000: Continue to batch restore \ue001: Back": "\ue000:继续批量还原 \ue001:返回", 194 | "\ue000: Ok! Go to Title selection \ue001: Back": "\ue000:完成!打开软件选择 \ue001:返回", 195 | "\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back": "\ue000:输入 \uE003: Shift \uE002:退格 \ue045:结束 \ue001:返回", 196 | "\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back": "\ue000:选择存檔集 \ue045:标记存檔集 \ue046:删除存檔集 \ue003:过滤器 \ue001:返回", 197 | "\ue003\ue07e: Select/Deselect \ue000: Restore selected titles \ue001: Back": "\ue003\ue07e:选择/取消选择 \ue000:还原所选应用 \ue001:返回", 198 | "same user than in source": "与备份数据的目标用户相同", 199 | "vWii Titles": "vWii软件", 200 | "|Restored|": "|已还原|", 201 | " BackupSet Management": " 存檔集管理", 202 | "BS: %s": "存檔集:%s", 203 | "pre-BatchRestore Backup (WiiU)": "预批量还原备份(WiiU)", 204 | "pre-BatchRestore Backup (vWii)": "预批量还原备份(vWii)", 205 | "pre-Restore backup": "预还原备份", 206 | "pre-Wipe backup": "预删除备份", 207 | "pre-copyToOtherDev backup": "预复制到其它设备备份", 208 | "UNUSABLE SLOT - BACKUP FAILED": "无法使用的槽位!备份失败!", 209 | "Cannot open file for read\n\n%s\n%s": "无法打开文件进行读取\n\n%s\n%s", 210 | "Cannot open file for write\n\n%s\n%s": "无法打开文件进行写入\n\n%s\n%s", 211 | "Error opening source dir\n\n%s\n%s": "打开源目录出错\n\n%s\n%s", 212 | "Read error\n%s": "读取错误\n%s", 213 | "Write error\n%s": "写入错误\n%s", 214 | "\ue002: Change BackupSet \ue000: Restore \ue045 Tag Slot \ue001: Back": "\ue002:更改存檔集 \ue000:还原 \ue045:标记槽位 \ue001:返回", 215 | "Error while creating final folder:\n\n%s\n%lx": "创建最终文件夹时出错:\n\n%s\n%lx", 216 | "Error while creating folder:\n\n%s\n%lx": "创建文件夹时出错:\n\n%s\n%lx", 217 | "Error while creating folder:\n\n%s\n%s": "创建文件夹时出错:\n\n%s\n%s", 218 | "Initializing FS": "初始化FS", 219 | "Please wait. First write to (some) SDs can take several seconds.": "请稍候。首次写入SD卡可能需要几秒钟。", 220 | "KB_N_0": "1234567890-=", 221 | "KB_N_1": "qwertyuiop[]|", 222 | "KB_N_2": "asdfghjkl;'", 223 | "KB_N_3": "zxcvbnm ,./", 224 | "KB_S_0": "!@#$%^&*()_+~", 225 | "KB_S_1": "QWERTYUIOP{}\\", 226 | "KB_S_2": "ASDFGHJKL:\"", 227 | "KB_S_3": "ZXCVBNM <>" 228 | } -------------------------------------------------------------------------------- /src/BackupSetList.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | bool BackupSetList::sortAscending = false; 13 | const std::string BackupSetList::ROOT_BS = ">> Root <<"; 14 | std::string BackupSetList::backupSetSubPath = "/";; 15 | std::string BackupSetList::backupSetEntry = ROOT_BS; 16 | std::string BackupSetList::savedBackupSetSubPath {}; 17 | 18 | std::unique_ptr BackupSetList::currentBackupSetList = std::make_unique(); 19 | 20 | extern const char *batchBackupPath; 21 | 22 | BackupSetList::BackupSetList(const char *backupSetListRoot) 23 | { 24 | 25 | this->backupSetListRoot = backupSetListRoot; 26 | 27 | BSMetadata bsm; 28 | 29 | backupSets.push_back(BackupSetItem(ROOT_BS,bsm)); 30 | bsMetadataValues.year.range.insert("*"); 31 | bsMetadataValues.month.range.insert("*"); 32 | bsMetadataValues.serialId.range.insert("*"); 33 | bsMetadataValues.tag.range.insert("*"); 34 | v2b.push_back(0); 35 | 36 | DIR *dir = opendir(backupSetListRoot); 37 | if (dir != nullptr) { 38 | struct dirent *data; 39 | while ((data = readdir(dir)) != nullptr) { 40 | if(strcmp(data->d_name,".") == 0 || strcmp(data->d_name,"..") == 0 || ! (data->d_type & DT_DIR)) 41 | continue; 42 | 43 | std::string metadataPath = data->d_name; 44 | Metadata metadata(std::string(batchBackupPath)+"/"+metadataPath); 45 | if(!metadata.read()) { 46 | metadata.write(); 47 | } 48 | bsm = BSMetadata(metadata.getDate().substr(0,4),metadata.getDate().size()>6 ? metadata.getDate().substr(5,2) : "", 49 | metadata.getSerialId(),metadata.getTag()); 50 | backupSets.push_back(BackupSetItem(data->d_name,bsm)); 51 | if (bsm.year != "") 52 | bsMetadataValues.year.range.insert(bsm.year); 53 | if (bsm.month != "") 54 | bsMetadataValues.month.range.insert(bsm.month); 55 | bsMetadataValues.serialId.range.insert(bsm.serialId); 56 | if (bsm.tag != "") 57 | bsMetadataValues.tag.range.insert(bsm.tag); 58 | } 59 | } 60 | closedir(dir); 61 | 62 | this->entries = this->backupSets.size(); 63 | 64 | BackupSetItemView bsiv; 65 | for (int i=0;i < this->entries;i++) { 66 | bsiv.entryPath = backupSets[i].entryPath; 67 | bsiv.serialId = backupSets[i].bsItemMetadata.serialId; 68 | bsiv.tag = backupSets[i].bsItemMetadata.tag; 69 | this->backupSetsView.push_back(bsiv); 70 | this->v2b.push_back(i); 71 | } 72 | 73 | this->entriesView = backupSetsView.size(); 74 | this->sort(sortAscending); 75 | 76 | bsMetadataValues.year.iterator = --bsMetadataValues.year.range.end(); 77 | bsMetadataValues.month.iterator = --bsMetadataValues.month.range.end(); 78 | bsMetadataValues.serialId.iterator = bsMetadataValues.serialId.range.begin(); 79 | bsMetadataValues.tag.iterator = bsMetadataValues.tag.range.begin(); 80 | } 81 | 82 | void BackupSetList::sort(bool sortAscending_) 83 | { 84 | if (sortAscending_) { 85 | std::ranges::sort(backupSetsView.begin()+1,backupSetsView.end(),std::ranges::less{},&BackupSetItemView::entryPath); 86 | } else { 87 | std::ranges::sort(backupSetsView.begin()+1,backupSetsView.end(),std::ranges::greater{},&BackupSetItemView::entryPath); 88 | } 89 | sortAscending = sortAscending_; 90 | } 91 | 92 | std::string BackupSetList::at(int i) { 93 | return backupSetsView.at(i).entryPath; 94 | } 95 | 96 | std::string BackupSetList::getSerialIdAt(int i) { 97 | return backupSetsView.at(i).serialId; 98 | } 99 | 100 | std::string BackupSetList::getStretchedSerialIdAt(int i) { 101 | int serialIdSize = getSerialIdAt(i).size(); 102 | return serialIdSize > 8 ? getSerialIdAt(i).substr(0,4)+".."+getSerialIdAt(i).substr(serialIdSize-4,4) : getSerialIdAt(i); 103 | } 104 | 105 | std::string BackupSetList::getTagAt(int i) { 106 | return backupSetsView.at(i).tag; 107 | } 108 | 109 | void BackupSetList::add(std::string entryPath,std::string serialId,std::string tag) 110 | { 111 | BackupSetItemView bsiv; 112 | bsiv.entryPath = entryPath; 113 | bsiv.serialId = serialId; 114 | bsiv.tag = tag; 115 | backupSetsView.push_back(bsiv); 116 | this->entriesView++; 117 | if (!sortAscending) 118 | this->sort(false); 119 | } 120 | 121 | 122 | void BackupSetList::initBackupSetList() { 123 | BackupSetList::currentBackupSetList.reset(); 124 | BackupSetList::currentBackupSetList = std::make_unique(batchBackupPath); 125 | } 126 | 127 | void BackupSetList::setBackupSetEntry(int i) { 128 | backupSetEntry = currentBackupSetList->at(i); 129 | } 130 | 131 | void BackupSetList::setBackupSetSubPath() { 132 | if (backupSetEntry == ROOT_BS) 133 | backupSetSubPath = "/"; 134 | else 135 | backupSetSubPath = "/batch/"+backupSetEntry+"/"; 136 | } 137 | 138 | std::string BackupSetList::getBackupSetSubPath(int i) { 139 | if (i == 0) 140 | return "/"; 141 | else 142 | return "/batch/"+currentBackupSetList->at(i)+"/"; 143 | } 144 | 145 | void BackupSetList::filter(BSMetadata filterDef) { 146 | 147 | backupSetsView.erase(backupSetsView.begin()+1,backupSetsView.end()); 148 | v2b.erase(v2b.begin()+1,v2b.end()); 149 | BackupSetItemView bsiv; 150 | for (unsigned int i=1; i < this->backupSets.size(); i++) { 151 | if (filterDef.year == "*" || filterDef.year == this->backupSets[i].bsItemMetadata.year) 152 | if (filterDef.month == "*" || filterDef.month == this->backupSets[i].bsItemMetadata.month) 153 | if (filterDef.serialId == "*" || filterDef.serialId == this->backupSets[i].bsItemMetadata.serialId) 154 | if (filterDef.tag == "*" || filterDef.tag == this->backupSets[i].bsItemMetadata.tag) { 155 | bsiv.entryPath = backupSets[i].entryPath; 156 | bsiv.serialId = backupSets[i].bsItemMetadata.serialId; 157 | bsiv.tag = backupSets[i].bsItemMetadata.tag; 158 | this->backupSetsView.push_back(bsiv); 159 | this->v2b.push_back(i); 160 | } 161 | } 162 | this->entriesView = this->backupSetsView.size(); 163 | } 164 | 165 | void BackupSetList::filter() { 166 | backupSetsView.erase(backupSetsView.begin()+1,backupSetsView.end()); 167 | BackupSetItemView bsiv; 168 | for (unsigned int i=1; i < this->backupSets.size(); i++) { 169 | if (*bsMetadataValues.year.iterator == "*" || *bsMetadataValues.year.iterator == this->backupSets[i].bsItemMetadata.year) 170 | if (*bsMetadataValues.month.iterator == "*" || *bsMetadataValues.month.iterator == this->backupSets[i].bsItemMetadata.month) 171 | if (*bsMetadataValues.serialId.iterator == "*" || *bsMetadataValues.serialId.iterator == this->backupSets[i].bsItemMetadata.serialId) 172 | if (*bsMetadataValues.tag.iterator == "*" || *bsMetadataValues.tag.iterator == this->backupSets[i].bsItemMetadata.tag) { 173 | bsiv.entryPath = backupSets[i].entryPath; 174 | bsiv.serialId = backupSets[i].bsItemMetadata.serialId; 175 | bsiv.tag = backupSets[i].bsItemMetadata.tag; 176 | this->backupSetsView.push_back(bsiv); 177 | } 178 | } 179 | this->entriesView = this->backupSetsView.size(); 180 | } 181 | 182 | void BackupSetList::resetTagRange() { 183 | bsMetadataValues.tag.range.erase(bsMetadataValues.tag.range.begin(),bsMetadataValues.tag.range.end()); 184 | for (unsigned int i=0;i < this->backupSets.size();i++) { 185 | if (backupSets[i].bsItemMetadata.tag != "") 186 | bsMetadataValues.tag.range.insert(backupSets[i].bsItemMetadata.tag); 187 | } 188 | bsMetadataValues.tag.iterator = bsMetadataValues.tag.range.begin(); 189 | } 190 | 191 | void BSMetadataValues::resetFilter() { 192 | this->year.iterator = --this->year.range.end(); 193 | this->month.iterator = --this->month.range.end(); 194 | this->serialId.iterator = this->serialId.range.begin(); 195 | this->tag.iterator = this->tag.range.begin(); 196 | } 197 | 198 | void BackupSetList::setTagBSVAt(int i, const std::string & tag) { 199 | this->backupSetsView[i].tag = tag; 200 | } 201 | 202 | void BackupSetList::setTagBSAt(int i, const std::string & tag_) { 203 | this->backupSets[i].bsItemMetadata.tag = tag_; 204 | } 205 | 206 | template < typename T > 207 | void BSMetadataValues::Right( T & metadataAttr ) { 208 | metadataAttr.iterator++; 209 | if (metadataAttr.iterator == metadataAttr.range.end()) 210 | metadataAttr.iterator = metadataAttr.range.begin(); 211 | } 212 | 213 | template < typename T > 214 | void BSMetadataValues::Left(T & metadataAttr ) { 215 | if (metadataAttr.iterator == metadataAttr.range.begin()) 216 | metadataAttr.iterator = --metadataAttr.range.end(); 217 | else 218 | metadataAttr.iterator--; 219 | } 220 | 221 | template void BSMetadataValues::Right(attr> &); 222 | template void BSMetadataValues::Right(attr> &); 223 | template void BSMetadataValues::Left(attr> &); 224 | template void BSMetadataValues::Left(attr> &); 225 | 226 | 227 | -------------------------------------------------------------------------------- /src/Metadata.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define FS_ALIGN(x) ((x + 0x3F) & ~(0x3F)) 6 | 7 | std::string Metadata::unknownSerialId { "_WIIU_" }; 8 | std::string Metadata::thisConsoleSerialId = Metadata::unknownSerialId; 9 | 10 | bool Metadata::read() { 11 | if (checkEntry(this->path.c_str()) != 0) { 12 | FILE *f = fopen(this->path.c_str(), "rb"); 13 | fseek(f, 0, SEEK_END); 14 | long len = ftell(f); 15 | fseek(f, 0, SEEK_SET); 16 | 17 | char *data = (char *) aligned_alloc(0x40, FS_ALIGN(len + 1)); 18 | 19 | fread(data, 1, len, f); 20 | data[len] = '\0'; 21 | fclose(f); 22 | 23 | json_error_t error; 24 | json_t *root = json_loads(data, 0, &error); 25 | 26 | if (root) { 27 | std::string metadata {}; 28 | const char* Date = json_string_value(json_object_get(root, "Date")); 29 | if (Date != nullptr) { 30 | this->Date.assign(Date); 31 | } 32 | const char* storage = json_string_value(json_object_get(root, "storage")); 33 | if (storage != nullptr) { 34 | this->storage.assign(storage); 35 | } 36 | const char* serialId = json_string_value(json_object_get(root, "serialId")); 37 | if (serialId != nullptr) { 38 | this->serialId.assign(serialId); 39 | } 40 | const char* tag = json_string_value(json_object_get(root, "tag")); 41 | if (tag != nullptr) { 42 | this->tag.assign(tag); 43 | } 44 | json_decref(root); 45 | free(data); 46 | return true; 47 | } 48 | } 49 | return false; 50 | } 51 | 52 | std::string Metadata::get() { 53 | if (read()) { 54 | std::string metadataMessage {}; 55 | metadataMessage.assign(this->Date); 56 | if (this->storage != "") 57 | metadataMessage.append(LanguageUtils::gettext(", from ")).append(this->storage); 58 | metadataMessage.append(" | ").append(this->serialId); 59 | return metadataMessage; 60 | } 61 | return ""; 62 | } 63 | 64 | std::string Metadata::simpleFormat() { 65 | if (this->Date != "") { 66 | std::string metadataMessage {}; 67 | metadataMessage.assign(this->Date); 68 | if (this->storage != "") 69 | metadataMessage.append(LanguageUtils::gettext(", from ")).append(this->storage); 70 | metadataMessage.append(" | ").append(this->serialId); 71 | return metadataMessage; 72 | } 73 | return ""; 74 | } 75 | 76 | bool Metadata::set(const std::string &date, bool isUSB) { 77 | 78 | this->Date = date; 79 | this->storage = isUSB ? "USB" : "NAND"; 80 | this->serialId = thisConsoleSerialId; 81 | 82 | return write(); 83 | } 84 | 85 | bool Metadata::write() { 86 | json_t *config = json_object(); 87 | if (config == nullptr) 88 | return false; 89 | 90 | json_object_set_new(config, "Date", json_string(this->Date.c_str())); 91 | json_object_set_new(config, "serialId", json_string(this->serialId.c_str())); 92 | json_object_set_new(config, "storage", json_string(this->storage.c_str())); 93 | json_object_set_new(config, "tag", json_string(this->tag.c_str())); 94 | 95 | char *configString = json_dumps(config, 0); 96 | if (configString == nullptr) 97 | return false; 98 | 99 | json_decref(config); 100 | 101 | FILE *fp = fopen(this->path.c_str(), "wb"); 102 | if (fp == nullptr) 103 | return false; 104 | 105 | fwrite(configString, strlen(configString), 1, fp); 106 | 107 | fclose(fp); 108 | return true; 109 | } 110 | -------------------------------------------------------------------------------- /src/cfg/BaseCfg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | BaseCfg::BaseCfg(const std::string & cfg) : cfg(cfg) { 10 | 11 | cfgFile = cfgPath+"/savemii-"+Metadata::thisConsoleSerialId+"-"+cfg+".json"; 12 | 13 | } 14 | 15 | bool BaseCfg::init() { 16 | int checkCfgPath = checkEntry(cfgPath.c_str()); 17 | if ( checkCfgPath == 2 ) 18 | goto backupPathExists; 19 | else { 20 | if ( checkCfgPath == 0 ) { 21 | if ( createFolder(cfgPath.c_str())) 22 | goto backupPathExists; 23 | else { 24 | std::string multilinePath; 25 | splitStringWithNewLines(cfgPath,multilinePath); 26 | promptError(LanguageUtils::gettext("Error while creating folder:\n\n%s\n%s"),multilinePath.c_str(),strerror(errno)); 27 | initialized = false; 28 | return false; 29 | } 30 | } 31 | else { 32 | std::string multilinePath; 33 | splitStringWithNewLines(cfgPath,multilinePath); 34 | promptError(LanguageUtils::gettext("Critical - Path is not a directory:\n\n%s"),multilinePath.c_str()); 35 | initialized = false; 36 | return false; 37 | } 38 | } 39 | 40 | backupPathExists: 41 | if ( checkEntry(cfgFile.c_str()) != 1 ) // no cfg file, create it with default values 42 | save(); 43 | 44 | initialized = true; 45 | 46 | return true; 47 | 48 | } 49 | 50 | bool BaseCfg::saveFile() { 51 | FILE *fp = fopen(cfgFile.c_str(), "wb"); 52 | if (fp == nullptr) { 53 | std::string multilinePath; 54 | splitStringWithNewLines(cfgFile,multilinePath); 55 | promptError(LanguageUtils::gettext("Cannot open file for write\n\n%s\n%s"),multilinePath.c_str(),strerror(errno)); 56 | return false; 57 | } 58 | if ( fwrite(configString, strlen(configString), 1, fp) == 0 ) 59 | if ( ferror(fp)) { 60 | std::string multilinePath; 61 | splitStringWithNewLines(cfgFile,multilinePath); 62 | promptError(LanguageUtils::gettext("Error writing file\n\n%s\n%s"),multilinePath.c_str(),strerror(errno)); 63 | fclose(fp); 64 | return false; 65 | } 66 | if ( fclose(fp) != 0) { 67 | std::string multilinePath; 68 | splitStringWithNewLines(cfgFile,multilinePath); 69 | promptError(LanguageUtils::gettext("Error closing file\n\n%s\n%s"),multilinePath.c_str(),strerror(errno)); 70 | return false; 71 | } 72 | 73 | return true; 74 | } 75 | 76 | 77 | 78 | bool BaseCfg::save() { 79 | if(mkJsonCfg()) 80 | if(saveFile()) 81 | return true; 82 | 83 | return false; 84 | } 85 | 86 | 87 | 88 | bool BaseCfg::readFile() { 89 | 90 | if ( initialized == false ) { 91 | std::string multilinePath; 92 | splitStringWithNewLines(cfgPath,multilinePath); 93 | promptError(LanguageUtils::gettext("cfgPath was no initialized and cannot be used:\n\n%s"),multilinePath.c_str()); 94 | return false; 95 | } 96 | 97 | FILE *fp = fopen(cfgFile.c_str(), "rb"); 98 | if (fp == nullptr) { 99 | std::string multilinePath; 100 | splitStringWithNewLines(cfgFile,multilinePath); 101 | promptError(LanguageUtils::gettext("Cannot open file for read\n\n%s\n%s"),multilinePath.c_str(),strerror(errno)); 102 | return false; 103 | } 104 | 105 | fseek(fp, 0, SEEK_END); 106 | long len = ftell(fp); 107 | fseek(fp, 0, SEEK_SET); 108 | 109 | configString = (char *) malloc(len+1); 110 | 111 | if ( fread(configString, 1, len, fp) == 0 ) 112 | if ( ferror(fp)) 113 | { 114 | std::string multilinePath; 115 | splitStringWithNewLines(cfgFile,multilinePath); 116 | promptError(LanguageUtils::gettext("Error reading file\n\n%s\n%s"),multilinePath.c_str(),strerror(errno)); 117 | fclose(fp); 118 | return false; 119 | } 120 | configString[len] = '\0'; 121 | if ( fclose(fp) != 0) { 122 | std::string multilinePath; 123 | splitStringWithNewLines(cfgFile,multilinePath); 124 | promptError(LanguageUtils::gettext("Error closing file\n\n%s\n%s"),multilinePath.c_str(),strerror(errno)); 125 | return false; 126 | } 127 | 128 | return true; 129 | 130 | } 131 | 132 | bool BaseCfg::read() { 133 | if(readFile()) 134 | if(parseJsonCfg()) 135 | return true; 136 | 137 | return false; 138 | } 139 | 140 | -------------------------------------------------------------------------------- /src/cfg/ExcludesCfg.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | ExcludesCfg::ExcludesCfg(const std::string & cfg,Title* titles , int titlesCount) : 8 | BaseCfg(cfg), 9 | titles(titles), 10 | titlesCount(titlesCount) {} 11 | 12 | bool ExcludesCfg::getConfig() { 13 | 14 | titlesID.clear(); 15 | 16 | for (int i=0;i(std::stoul(hID_,nullptr,16)); 149 | titleID.lowID = static_cast(std::stoul(lID_,nullptr,16)); 150 | titleID.isTitleOnUSB = json_boolean_value(u); 151 | titlesID.push_back(titleID); 152 | 153 | } 154 | 155 | if (errorCount != 0 ) { 156 | std::string multilineError; 157 | splitStringWithNewLines(koElements,multilineError); 158 | promptError(LanguageUtils::gettext("Error parsing values in elements:\n%s"),multilineError.c_str()); 159 | } 160 | 161 | return (errorCount == 0); 162 | } 163 | 164 | bool ExcludesCfg::applyConfig() { 165 | 166 | for (const titleID& titleID : titlesID) { 167 | for (int i = 0; i < titlesCount; i++) { 168 | if ( titles[i].lowID == titleID.lowID) 169 | if (titles[i].highID == titleID.highID) 170 | if (titles[i].isTitleOnUSB == titleID.isTitleOnUSB) { 171 | titles[i].currentBackup.selectedToBackup = false; 172 | break; 173 | } 174 | } 175 | } 176 | 177 | return true; 178 | } 179 | -------------------------------------------------------------------------------- /src/cfg/GlobalCfg.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | GlobalCfg::GlobalCfg(const std::string & cfg) : 10 | BaseCfg(cfg) { 11 | // set Defaults 12 | Language = LanguageUtils::getSystemLanguage(); 13 | alwaysApplyExcludes = false; 14 | } 15 | 16 | bool GlobalCfg::mkJsonCfg() { 17 | 18 | 19 | json_t *config = json_object(); 20 | if (config == nullptr) { 21 | promptError(LanguageUtils::gettext("Error creating JSON object: %s"),cfg.c_str()); 22 | return false; 23 | } 24 | 25 | json_object_set_new(config, "language", json_integer(Language)); 26 | json_object_set_new(config, "alwaysApplyExcludes", json_boolean(alwaysApplyExcludes)); 27 | 28 | configString = json_dumps(config, 0); 29 | json_decref(config); 30 | if (configString == nullptr) { 31 | promptError(LanguageUtils::gettext("Error dumping JSON object: %s"),cfg.c_str()); 32 | return false; 33 | } 34 | 35 | return true; 36 | } 37 | 38 | bool GlobalCfg::parseJsonCfg() { 39 | 40 | json_t* root; 41 | json_error_t error; 42 | 43 | root = json_loads(configString,0,&error); 44 | free(configString); 45 | 46 | if (!root) 47 | { 48 | std::string multilinePath; 49 | splitStringWithNewLines(cfgFile,multilinePath); 50 | promptError(LanguageUtils::gettext("Error decoding JSON file\n %s\nin line %d:\n\n%s"),multilinePath.c_str(),error.line,error.text); 51 | return false; 52 | } 53 | 54 | json_t* language = json_object_get(root,"language"); 55 | if ( json_is_integer(language) ) { 56 | int languageType = json_integer_value(language); 57 | if (languageType >=0 || languageType <=12 ) 58 | Language = (Swkbd_LanguageType) languageType; 59 | } 60 | 61 | json_t* alwaysapplyexcludes = json_object_get(root,"alwaysApplyExcludes"); 62 | if ( json_is_boolean(alwaysapplyexcludes) ) 63 | alwaysApplyExcludes = json_boolean_value(alwaysapplyexcludes); 64 | 65 | json_decref(root); 66 | 67 | return true; 68 | 69 | 70 | } 71 | 72 | bool GlobalCfg::applyConfig() { 73 | 74 | LanguageUtils::loadLanguage(Language); 75 | return true; 76 | 77 | } 78 | 79 | bool GlobalCfg::getConfig() { 80 | 81 | Language = LanguageUtils::getSwkbdLoadedLang(); 82 | return true; 83 | 84 | } 85 | -------------------------------------------------------------------------------- /src/menu/BackupSetListFilter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void BackupSetListFilterState::render() { 13 | if (this->state == STATE_BACKUPSET_FILTER) { 14 | DrawUtils::setFontColor(COLOR_TEXT); 15 | consolePrintPosAligned(0,4,1,"Filter BackupSets"); 16 | DrawUtils::setFontColor(COLOR_INFO); 17 | consolePrintPos(0,4,LanguageUtils::gettext("Show only BackupSets satisfying all these conditions:")); 18 | DrawUtils::setFontColor(COLOR_TEXT); 19 | consolePrintPos(M_OFF, 6, "Console: %s", (*backupSetList->bsMetadataValues.serialId.iterator).c_str()); 20 | consolePrintPos(M_OFF, 7, "Tag: %s", (*backupSetList->bsMetadataValues.tag.iterator).c_str()); 21 | consolePrintPos(M_OFF, 8, "Month: %s", (*backupSetList->bsMetadataValues.month.iterator).c_str()); 22 | consolePrintPos(M_OFF, 9, "Year: %s", (*backupSetList->bsMetadataValues.year.iterator).c_str()); 23 | consolePrintPos(-1, 6 + cursorPos, "\u2192"); 24 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Apply Filter \uE002: Reset Filters \ue001: Back")); 25 | 26 | } 27 | } 28 | 29 | ApplicationState::eSubState BackupSetListFilterState::update(Input *input) { 30 | if (input->get(TRIGGER, PAD_BUTTON_B)) { 31 | return SUBSTATE_RETURN; 32 | } 33 | if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { 34 | switch (cursorPos) { 35 | case 0: 36 | BSMetadataValues::Left(backupSetList->bsMetadataValues.serialId); 37 | break; 38 | case 1: 39 | BSMetadataValues::Left(backupSetList->bsMetadataValues.tag); 40 | break; 41 | case 2: 42 | BSMetadataValues::Left(backupSetList->bsMetadataValues.month); 43 | break; 44 | case 3: 45 | BSMetadataValues::Left(backupSetList->bsMetadataValues.year); 46 | break; 47 | default: 48 | break; 49 | } 50 | } 51 | if (input->get(TRIGGER, PAD_BUTTON_RIGHT)) { 52 | switch (cursorPos) { 53 | case 0: 54 | BSMetadataValues::Right(backupSetList->bsMetadataValues.serialId); 55 | break; 56 | case 1: 57 | BSMetadataValues::Right(backupSetList->bsMetadataValues.tag); 58 | break; 59 | case 2: 60 | BSMetadataValues::Right(backupSetList->bsMetadataValues.month); 61 | break; 62 | case 3: 63 | BSMetadataValues::Right(backupSetList->bsMetadataValues.year); 64 | break; 65 | default: 66 | break; 67 | } 68 | } 69 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { 70 | if (entrycount <= 14) 71 | cursorPos = (cursorPos + 1) % entrycount; 72 | } 73 | if (input->get(TRIGGER, PAD_BUTTON_UP)) { 74 | if (cursorPos > 0) 75 | --cursorPos; 76 | } 77 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 78 | backupSetList->filter(); 79 | backupSetList->sort(BackupSetList::getSortAscending()); 80 | BackupSetListState::resetCursorAndScroll(); 81 | return SUBSTATE_RETURN; 82 | } 83 | if (input->get(TRIGGER,PAD_BUTTON_X)) { 84 | backupSetList->bsMetadataValues.resetFilter(); 85 | } 86 | return SUBSTATE_RUNNING; 87 | } -------------------------------------------------------------------------------- /src/menu/BackupSetListState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #define MAX_ROWS_SHOW 14 14 | 15 | int BackupSetListState::cursorPos = 0; 16 | int BackupSetListState::scroll = 0; 17 | static std::string language; 18 | 19 | BackupSetListState::BackupSetListState() { 20 | finalScreen = true; 21 | this->sortAscending = BackupSetList::sortAscending; 22 | if (BackupSetList::getIsInitializationRequired() ) { 23 | BackupSetList::initBackupSetList(); 24 | BackupSetListState::resetCursorPosition(); 25 | BackupSetList::setIsInitializationRequired(false); 26 | } 27 | } 28 | 29 | BackupSetListState::BackupSetListState(Title *titles, int titlesCount, bool isWiiUBatchRestore) : 30 | titles(titles), 31 | titlesCount(titlesCount), 32 | isWiiUBatchRestore(isWiiUBatchRestore) { 33 | finalScreen = false; 34 | if (BackupSetList::getIsInitializationRequired() ) { 35 | BackupSetList::initBackupSetList(); 36 | BackupSetListState::resetCursorPosition(); 37 | BackupSetList::setIsInitializationRequired(false); 38 | } 39 | } 40 | 41 | void BackupSetListState::resetCursorPosition() { // if bslist is modified after a new batch Backup 42 | if ( cursorPos == 0 ) 43 | return; 44 | if (BackupSetList::sortAscending) { 45 | return; 46 | } 47 | else { 48 | cursorPos++; 49 | } 50 | } 51 | 52 | void BackupSetListState::resetCursorAndScroll() { // if we apply a new filter 53 | cursorPos=0; 54 | scroll=0; 55 | } 56 | 57 | void BackupSetListState::render() { 58 | if (this->state == STATE_DO_SUBSTATE) { 59 | if (this->subState == nullptr) { 60 | OSFatal("SubState was null"); 61 | } 62 | this->subState->render(); 63 | return; 64 | } 65 | if (this->state == STATE_BACKUPSET_MENU) { 66 | std::string backupSetItem; 67 | DrawUtils::setFontColor(COLOR_INFO); 68 | if (BackupSetList::currentBackupSetList->entriesView == BackupSetList::currentBackupSetList->entries) { 69 | consolePrintPosAligned(0, 4, 1, LanguageUtils::gettext("BackupSets")); 70 | } else { 71 | consolePrintPosAligned(0, 4, 1, LanguageUtils::gettext("BackupSets (filter applied)")); 72 | } 73 | DrawUtils::setFontColor(COLOR_TEXT); 74 | consolePrintPosAligned(0,4,2, LanguageUtils::gettext("\ue083 Sort: %s \ue084"), 75 | this->sortAscending ? "\u2191" : "\u2193"); 76 | for (int i = 0; i < MAX_ROWS_SHOW; i++) { 77 | if (i + scroll < 0 || i + scroll >= BackupSetList::currentBackupSetList->entriesView) 78 | break; 79 | backupSetItem = BackupSetList::currentBackupSetList->at(i + scroll); 80 | 81 | 82 | DrawUtils::setFontColorByCursor(COLOR_LIST_NOSAVE,COLOR_LIST_NOSAVE_AT_CURSOR,cursorPos,i); 83 | 84 | DrawUtils::setFontColorByCursor(COLOR_LIST,COLOR_LIST_AT_CURSOR,cursorPos,i); 85 | if ( backupSetItem == BackupSetList::ROOT_BS) 86 | DrawUtils::setFontColorByCursor(COLOR_LIST_HIGH,COLOR_LIST_HIGH_AT_CURSOR,cursorPos,i); 87 | if ( backupSetItem == BackupSetList::getBackupSetEntry()) 88 | DrawUtils::setFontColorByCursor(COLOR_CURRENT_BS,COLOR_CURRENT_BS_AT_CURSOR,cursorPos,i); 89 | 90 | consolePrintPos(M_OFF-1, i + 2, " %s", backupSetItem.substr(0,15).c_str()); 91 | consolePrintPos(21, i+2,"%s", BackupSetList::currentBackupSetList->getStretchedSerialIdAt(i+scroll).c_str()); 92 | consolePrintPos(33, i+2,"%s", BackupSetList::currentBackupSetList->getTagAt(i+scroll).c_str()); 93 | } 94 | DrawUtils::setFontColor(COLOR_TEXT); 95 | consolePrintPos(-1, 2 + cursorPos, "\u2192"); 96 | if (cursorPos + scroll > 0) 97 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select BS \ue045: Tag BS \ue046: Wipe BS \ue003: Filter List \ue001: Back")); 98 | else 99 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select BackupSet \ue003: Filter List \ue001: Back")); 100 | } 101 | } 102 | 103 | ApplicationState::eSubState BackupSetListState::update(Input *input) { 104 | if (this->state == STATE_BACKUPSET_MENU) { 105 | if (input->get(TRIGGER, PAD_BUTTON_B)) 106 | return SUBSTATE_RETURN; 107 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 108 | if (! finalScreen) { 109 | if (cursorPos + scroll == 0) { 110 | promptError(LanguageUtils::gettext("Root BackupSet cannot be selected for batchRestore")); 111 | return SUBSTATE_RUNNING; 112 | } 113 | } 114 | BackupSetList::setBackupSetEntry(cursorPos + scroll); 115 | BackupSetList::setBackupSetSubPath(); 116 | //DrawUtils::setRedraw(true); 117 | if (finalScreen) { 118 | char message[256]; 119 | const char* messageTemplate = LanguageUtils::gettext("BackupSet selected:\n - TimeStamp: %s\n - Tag: %s\n - From console: %s\n\nThis console: %s"); 120 | snprintf(message,256,messageTemplate, 121 | BackupSetList::currentBackupSetList->at(cursorPos + scroll).c_str(), 122 | BackupSetList::currentBackupSetList->getTagAt(cursorPos+scroll).c_str(), 123 | BackupSetList::currentBackupSetList->getSerialIdAt(cursorPos+scroll).c_str(), 124 | Metadata::thisConsoleSerialId.c_str()); 125 | promptMessage(COLOR_BG_OK,message); 126 | DrawUtils::setRedraw(true); 127 | return SUBSTATE_RETURN; 128 | } 129 | else // is a step in batchRestore 130 | { 131 | this->state = STATE_DO_SUBSTATE; 132 | this->subState = std::make_unique(titles, titlesCount, isWiiUBatchRestore); 133 | } 134 | } 135 | if (input->get(TRIGGER, PAD_BUTTON_Y)) { 136 | this->state = STATE_DO_SUBSTATE; 137 | this->substateCalled = STATE_BACKUPSET_FILTER; 138 | this->subState = std::make_unique(BackupSetList::currentBackupSetList); 139 | } 140 | if (input->get(TRIGGER, PAD_BUTTON_L)) { 141 | if ( this->sortAscending ) { 142 | this->sortAscending = false; 143 | BackupSetList::currentBackupSetList->sort(this->sortAscending); 144 | cursorPos = 0; 145 | scroll = 0; 146 | } 147 | } 148 | if (input->get(TRIGGER, PAD_BUTTON_R)) { 149 | if ( ! this->sortAscending ) { 150 | this->sortAscending = true; 151 | BackupSetList::currentBackupSetList->sort(this->sortAscending); 152 | cursorPos = 0; 153 | scroll = 0; 154 | } 155 | } 156 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { 157 | if (BackupSetList::currentBackupSetList->entriesView <= MAX_ROWS_SHOW) 158 | cursorPos = (cursorPos + 1) % BackupSetList::currentBackupSetList->entriesView; 159 | else if (cursorPos < 6) 160 | cursorPos++; 161 | else if (((cursorPos + scroll + 1) % BackupSetList::currentBackupSetList->entriesView) != 0) 162 | scroll++; 163 | else 164 | cursorPos = scroll = 0; 165 | tag = BackupSetList::currentBackupSetList->getTagAt(cursorPos+scroll); 166 | newTag = tag; 167 | } 168 | if (input->get(TRIGGER, PAD_BUTTON_UP)) { 169 | if (scroll > 0) 170 | cursorPos -= (cursorPos > 6) ? 1 : 0 * (scroll--); 171 | else if (cursorPos > 0) 172 | cursorPos--; 173 | else if (BackupSetList::currentBackupSetList->entriesView > MAX_ROWS_SHOW) 174 | scroll = BackupSetList::currentBackupSetList->entriesView - (cursorPos = 6) - 1; 175 | else 176 | cursorPos = BackupSetList::currentBackupSetList->entriesView - 1; 177 | tag = BackupSetList::currentBackupSetList->getTagAt(cursorPos+scroll); 178 | newTag = tag; 179 | } 180 | if (input->get(TRIGGER, PAD_BUTTON_MINUS)) { 181 | int entry = cursorPos+scroll; 182 | if (entry > 0) 183 | { 184 | if (BackupSetList::getBackupSetSubPath() == BackupSetList::getBackupSetSubPath(entry)) 185 | { 186 | BackupSetList::setBackupSetEntry(entry-1); 187 | BackupSetList::setBackupSetSubPath(); 188 | } 189 | if ( wipeBackupSet(BackupSetList::getBackupSetSubPath(entry))) 190 | { 191 | BackupSetList::initBackupSetList(); 192 | cursorPos--; 193 | } 194 | DrawUtils::setRedraw(true); 195 | } 196 | } 197 | if (input->get(TRIGGER, PAD_BUTTON_PLUS)) { 198 | int entry = cursorPos+scroll; 199 | if (entry > 0) 200 | { 201 | this->state = STATE_DO_SUBSTATE; 202 | this->substateCalled = STATE_KEYBOARD; 203 | this->subState = std::make_unique(newTag); 204 | } 205 | } 206 | } else if (this->state == STATE_DO_SUBSTATE) { 207 | auto retSubState = this->subState->update(input); 208 | if (retSubState == SUBSTATE_RUNNING) { 209 | // keep running. 210 | return SUBSTATE_RUNNING; 211 | } else if (retSubState == SUBSTATE_RETURN) { 212 | if (this->substateCalled == STATE_KEYBOARD) { 213 | if ( tag != newTag ) { 214 | std::string entryPath = BackupSetList::currentBackupSetList->at(cursorPos + scroll); 215 | Metadata *metadataObj = new Metadata(getBatchBackupPathRoot(entryPath)); 216 | metadataObj->read(); 217 | metadataObj->setTag(newTag); 218 | metadataObj->write(); 219 | BackupSetList::currentBackupSetList->setTagBSVAt(cursorPos + scroll,newTag); 220 | BackupSetList::currentBackupSetList->setTagBSAt(BackupSetList::currentBackupSetList->v2b[cursorPos + scroll],newTag); 221 | if (newTag != "") 222 | BackupSetList::currentBackupSetList->resetTagRange(); 223 | delete metadataObj; 224 | } 225 | } 226 | if (BackupSetList::getIsInitializationRequired() ) { 227 | BackupSetList::initBackupSetList(); 228 | BackupSetListState::resetCursorPosition(); 229 | BackupSetList::setIsInitializationRequired(false); 230 | } 231 | this->subState.reset(); 232 | this->state = STATE_BACKUPSET_MENU; 233 | this->substateCalled = NONE; 234 | } 235 | } 236 | return SUBSTATE_RUNNING; 237 | } -------------------------------------------------------------------------------- /src/menu/BatchBackupState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #define ENTRYCOUNT 3 15 | 16 | static int cursorPos = 0; 17 | 18 | void BatchBackupState::render() { 19 | if (this->state == STATE_DO_SUBSTATE) { 20 | if (this->subState == nullptr) { 21 | OSFatal("SubState was null"); 22 | } 23 | this->subState->render(); 24 | return; 25 | } 26 | if (this->state == STATE_BATCH_BACKUP_MENU) { 27 | DrawUtils::setFontColor(COLOR_INFO); 28 | consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Batch Backup")); 29 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); 30 | consolePrintPos(M_OFF, 2, LanguageUtils::gettext(" Backup All (%u Title%s)"), this->wiiuTitlesCount + this->vWiiTitlesCount, 31 | ((this->wiiuTitlesCount + this->vWiiTitlesCount) > 1) ? "s" : ""); 32 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); 33 | consolePrintPos(M_OFF, 3, LanguageUtils::gettext(" Backup Wii U (%u Title%s)"), this->wiiuTitlesCount, 34 | (this->wiiuTitlesCount > 1) ? "s" : ""); 35 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); 36 | consolePrintPos(M_OFF, 4, LanguageUtils::gettext(" Backup vWii (%u Title%s)"), this->vWiiTitlesCount, 37 | (this->vWiiTitlesCount > 1) ? "s" : ""); 38 | 39 | if (GlobalCfg::global->getAlwaysApplyExcludes()) { 40 | DrawUtils::setFontColor(COLOR_INFO); 41 | consolePrintPos(M_OFF+9,8, 42 | LanguageUtils::gettext("Reminder: Your Excludes will be applied to\n 'Backup Wii U' and 'Backup vWii' tasks")); 43 | } 44 | DrawUtils::setFontColor(COLOR_TEXT); 45 | consolePrintPos(M_OFF, 2 + cursorPos, "\u2192"); 46 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Backup \ue001: Back")); 47 | } 48 | } 49 | 50 | ApplicationState::eSubState BatchBackupState::update(Input *input) { 51 | if (this->state == STATE_BATCH_BACKUP_MENU) { 52 | if (input->get(TRIGGER, PAD_BUTTON_UP)) 53 | if (--cursorPos == -1) 54 | ++cursorPos; 55 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) 56 | if (++cursorPos == ENTRYCOUNT) 57 | --cursorPos; 58 | if (input->get(TRIGGER, PAD_BUTTON_B)) 59 | return SUBSTATE_RETURN; 60 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 61 | const std::string batchDatetime = getNowDateForFolder(); 62 | switch (cursorPos) { 63 | case 0: 64 | backupAllSave(this->wiiutitles, this->wiiuTitlesCount, batchDatetime); 65 | backupAllSave(this->wiititles, this->vWiiTitlesCount, batchDatetime); 66 | writeBackupAllMetadata(batchDatetime,"WiiU and vWii titles"); 67 | BackupSetList::setIsInitializationRequired(true); 68 | DrawUtils::setRedraw(true); 69 | break; 70 | case 1: 71 | this->state = STATE_DO_SUBSTATE; 72 | this->subState = std::make_unique(this->wiiutitles, this->wiiuTitlesCount, true,ExcludesCfg::wiiuExcludes); 73 | break; 74 | case 2: 75 | this->state = STATE_DO_SUBSTATE; 76 | this->subState = std::make_unique(this->wiititles, this->vWiiTitlesCount, false,ExcludesCfg::wiiExcludes); 77 | break; 78 | default: 79 | return SUBSTATE_RUNNING; 80 | } 81 | } 82 | } else if (this->state == STATE_DO_SUBSTATE) { 83 | auto retSubState = this->subState->update(input); 84 | if (retSubState == SUBSTATE_RUNNING) { 85 | // keep running. 86 | return SUBSTATE_RUNNING; 87 | } else if (retSubState == SUBSTATE_RETURN) { 88 | this->subState.reset(); 89 | this->state = STATE_BATCH_BACKUP_MENU; 90 | } 91 | } 92 | return SUBSTATE_RUNNING; 93 | } -------------------------------------------------------------------------------- /src/menu/BatchRestoreOptions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | //#define DEBUG 11 | #ifdef DEBUG 12 | #include 13 | #include 14 | #endif 15 | 16 | #define ENTRYCOUNT 5 17 | 18 | extern Account *sdacc; 19 | extern uint8_t sdaccn; 20 | 21 | BatchRestoreOptions::BatchRestoreOptions(Title *titles, 22 | int titlesCount,bool isWiiUBatchRestore) : titles(titles), 23 | titlesCount(titlesCount), isWiiUBatchRestore(isWiiUBatchRestore) { 24 | minCursorPos = isWiiUBatchRestore ? 0 : 3; 25 | cursorPos = minCursorPos; 26 | for (int i = 0; ititlesCount; i++) { 27 | this->titles[i].currentBackup= { 28 | .hasBatchBackup = false, 29 | .candidateToBeRestored = false, 30 | .selectedToRestore = false, 31 | .hasUserSavedata = false, 32 | .hasCommonSavedata = false, 33 | .batchRestoreState = NOT_TRIED 34 | }; 35 | if (this->titles[i].highID == 0 || this->titles[i].lowID == 0) 36 | continue; 37 | //if (! this->titles[i].saveInit) // we allow uninitializedTitles 38 | // continue; 39 | if (this->titles[i].isTitleDupe && ! this->titles[i].isTitleOnUSB) 40 | continue; 41 | if (strcmp(this->titles[i].shortName, "DONT TOUCH ME") == 0) // skip CBHC savedata 42 | continue; 43 | if (this->titles[i].is_Wii && isWiiUBatchRestore) // wii titles installed as wiiU appear in vWii restore 44 | continue; 45 | uint32_t highID = this->titles[i].highID; 46 | uint32_t lowID = this->titles[i].lowID; 47 | std::string srcPath = getDynamicBackupPath(highID, lowID, 0); 48 | DIR *dir = opendir(srcPath.c_str()); 49 | if (dir != nullptr) { 50 | if (isWiiUBatchRestore) { 51 | struct dirent *data; 52 | while ((data = readdir(dir)) != nullptr) { 53 | if(strcmp(data->d_name,".") == 0 || strcmp(data->d_name,"..") == 0 || ! (data->d_type & DT_DIR)) 54 | continue; 55 | if (data->d_name[0] == '8') 56 | batchSDUsers.insert(data->d_name); 57 | this->titles[i].currentBackup.hasBatchBackup=true; 58 | } 59 | } else { 60 | this->titles[i].currentBackup.hasBatchBackup = ! folderEmpty (srcPath.c_str()); 61 | } 62 | 63 | } 64 | closedir(dir); 65 | } 66 | 67 | if (sdacc != nullptr) 68 | free(sdacc); 69 | sdaccn = batchSDUsers.size(); 70 | 71 | int i=0; 72 | sdacc = (Account *) malloc(sdaccn * sizeof(Account)); 73 | for ( auto user : batchSDUsers ) { 74 | strcpy(sdacc[i].persistentID,user.substr(0,8).c_str()); 75 | sdacc[i].pID = strtoul(user.c_str(), nullptr, 16); 76 | sdacc[i].slot = i; 77 | i++; 78 | } 79 | } 80 | 81 | void BatchRestoreOptions::render() { 82 | if (this->state == STATE_DO_SUBSTATE) { 83 | if (this->subState == nullptr) { 84 | OSFatal("SubState was null"); 85 | } 86 | this->subState->render(); 87 | return; 88 | } 89 | 90 | if (this->state == STATE_BATCH_RESTORE_OPTIONS_MENU) { 91 | DrawUtils::setFontColor(COLOR_INFO); 92 | consolePrintPos(16,0, LanguageUtils::gettext("BatchRestore - Options")); 93 | DrawUtils::setFontColor(COLOR_INFO_AT_CURSOR); 94 | consolePrintPosAligned(0, 4, 2,LanguageUtils::gettext("BS: %s"),BackupSetList::getBackupSetEntry().c_str()); 95 | DrawUtils::setFontColor(COLOR_TEXT); 96 | if (isWiiUBatchRestore) { 97 | consolePrintPos(M_OFF, 3, LanguageUtils::gettext("Select SD user to copy from:")); 98 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); 99 | if (sduser == -1) 100 | consolePrintPos(M_OFF, 4, " < %s >", LanguageUtils::gettext("all users")); 101 | else 102 | consolePrintPos(M_OFF, 4, " < %s >", getSDacc()[sduser].persistentID); 103 | 104 | DrawUtils::setFontColor(COLOR_TEXT); 105 | consolePrintPos(M_OFF, 6 , LanguageUtils::gettext("Select Wii U user to copy to")); 106 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); 107 | if (this->wiiuuser == -1) 108 | consolePrintPos(M_OFF, 7, " < %s >", LanguageUtils::gettext("same user than in source")); 109 | else 110 | consolePrintPos(M_OFF, 7, " < %s (%s) >", 111 | getWiiUacc()[wiiuuser].miiName, getWiiUacc()[wiiuuser].persistentID); 112 | 113 | if (this->wiiuuser > -1) { 114 | DrawUtils::setFontColor(COLOR_TEXT); 115 | consolePrintPos(M_OFF, 9, LanguageUtils::gettext("Include 'common' save?")); 116 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); 117 | consolePrintPos(M_OFF, 10, " < %s >", common ? LanguageUtils::gettext("yes") : LanguageUtils::gettext("no ")); 118 | } 119 | } 120 | 121 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,3); 122 | consolePrintPos(M_OFF, 12 - (isWiiUBatchRestore ? 0 : 8) , LanguageUtils::gettext(" Wipe target users savedata before restoring: < %s >"), wipeBeforeRestore ? LanguageUtils::gettext("Yes") : LanguageUtils::gettext("No")); 123 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,4); 124 | consolePrintPos(M_OFF, 14 - (isWiiUBatchRestore ? 0 : 8), LanguageUtils::gettext(" Backup all data before restoring (strongly recommended): < %s >"), fullBackup ? LanguageUtils::gettext("Yes"):LanguageUtils::gettext("No")); 125 | 126 | DrawUtils::setFontColor(COLOR_TEXT); 127 | consolePrintPos(M_OFF, 4 + (cursorPos < 3 ? cursorPos * 3 : 3+(cursorPos-3)*2 + 5) - (isWiiUBatchRestore ? 0 : 8), "\u2192"); 128 | 129 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Ok! Go to Title selection \ue001: Back")); 130 | } 131 | } 132 | 133 | ApplicationState::eSubState BatchRestoreOptions::update(Input *input) { 134 | if (this->state == STATE_BATCH_RESTORE_OPTIONS_MENU) { 135 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 136 | this->state = STATE_DO_SUBSTATE; 137 | this->subState = std::make_unique(sduser, wiiuuser, common, wipeBeforeRestore, fullBackup, this->titles, this->titlesCount, isWiiUBatchRestore); 138 | } 139 | if (input->get(TRIGGER, PAD_BUTTON_B)) 140 | return SUBSTATE_RETURN; 141 | if (input->get(TRIGGER, PAD_BUTTON_X)) { 142 | this->state = STATE_DO_SUBSTATE; 143 | } 144 | if (input->get(TRIGGER, PAD_BUTTON_UP)) { 145 | if (--cursorPos < minCursorPos) 146 | ++cursorPos; 147 | if (cursorPos == 2 && sduser == -1 ) 148 | --cursorPos; 149 | } 150 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { 151 | if (++cursorPos == ENTRYCOUNT) 152 | --cursorPos; 153 | if (cursorPos == 2 && sduser == -1 ) 154 | ++cursorPos; 155 | } 156 | if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { 157 | switch (cursorPos) { 158 | case 0: 159 | sduser = ((sduser == -1) ? -1 : (sduser - 1)); 160 | this->wiiuuser = ((sduser == -1) ? -1 : this->wiiuuser); 161 | break; 162 | case 1: 163 | wiiuuser = (((wiiuuser == -1) || (sduser == -1)) ? -1 : (wiiuuser - 1)); 164 | wiiuuser = ((sduser > -1) && (wiiuuser == -1)) ? 0 : wiiuuser; 165 | break; 166 | case 2: 167 | common = common ? false : true; 168 | break; 169 | case 3: 170 | wipeBeforeRestore = wipeBeforeRestore ? false : true; 171 | break; 172 | case 4: 173 | fullBackup = fullBackup ? false : true; 174 | break; 175 | default: 176 | break; 177 | } 178 | } 179 | if (input->get(TRIGGER, PAD_BUTTON_RIGHT)) { 180 | switch (cursorPos) { 181 | case 0: 182 | sduser = ((sduser == (getSDaccn() - 1)) ? (getSDaccn() - 1) : (sduser + 1)); 183 | wiiuuser = ((sduser > -1) && (wiiuuser == -1)) ? 0 : wiiuuser; 184 | break; 185 | case 1: 186 | wiiuuser = ((wiiuuser == (getWiiUaccn() - 1)) ? (getWiiUaccn() - 1) : (wiiuuser + 1)); 187 | wiiuuser = (sduser == -1) ? -1 : wiiuuser; 188 | break; 189 | case 2: 190 | common = common ? false : true; 191 | break; 192 | case 3: 193 | wipeBeforeRestore = wipeBeforeRestore ? false : true; 194 | break; 195 | case 4: 196 | fullBackup = fullBackup ? false : true; 197 | break; 198 | default: 199 | break; 200 | } 201 | } 202 | } else if (this->state == STATE_DO_SUBSTATE) { 203 | auto retSubState = this->subState->update(input); 204 | if (retSubState == SUBSTATE_RUNNING) { 205 | // keep running. 206 | return SUBSTATE_RUNNING; 207 | } else if (retSubState == SUBSTATE_RETURN) { 208 | this->subState.reset(); 209 | this->state = STATE_BATCH_RESTORE_OPTIONS_MENU; 210 | } 211 | } 212 | return SUBSTATE_RUNNING; 213 | } -------------------------------------------------------------------------------- /src/menu/BatchRestoreState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #define ENTRYCOUNT 2 11 | 12 | static int cursorPos = 0; 13 | 14 | void BatchRestoreState::render() { 15 | if (this->state == STATE_DO_SUBSTATE) { 16 | if (this->subState == nullptr) { 17 | OSFatal("SubState was null"); 18 | } 19 | this->subState->render(); 20 | return; 21 | } 22 | if (this->state == STATE_BATCH_RESTORE_MENU) { 23 | DrawUtils::setFontColor(COLOR_INFO); 24 | consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Batch Restore")); 25 | DrawUtils::setFontColor(COLOR_TEXT); 26 | 27 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); 28 | consolePrintPos(M_OFF, 3, LanguageUtils::gettext(" Restore Wii U (%u Title%s)"), this->wiiuTitlesCount, 29 | (this->wiiuTitlesCount > 1) ? "s" : ""); 30 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); 31 | consolePrintPos(M_OFF, 4, LanguageUtils::gettext(" Restore vWii (%u Title%s)"), this->vWiiTitlesCount, 32 | (this->vWiiTitlesCount > 1) ? "s" : ""); 33 | DrawUtils::setFontColor(COLOR_TEXT); 34 | consolePrintPos(M_OFF, 3 + cursorPos, "\u2192"); 35 | DrawUtils::setFontColor(COLOR_INFO); 36 | consolePrintPos(M_OFF, 6, LanguageUtils::gettext("Batch Restore allows you to restore all savedata from a BatchBackup \n* to a different user in the same console \n* or to a different console where the games are previouly installed.\nIn the later case, it is recommended to first run the game to \n initialize the savedata.")); 37 | DrawUtils::setFontColor(COLOR_TEXT); 38 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Continue to batch restore \ue001: Back")); 39 | } 40 | } 41 | 42 | ApplicationState::eSubState BatchRestoreState::update(Input *input) { 43 | if (this->state == STATE_BATCH_RESTORE_MENU) { 44 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 45 | const std::string batchDatetime = getNowDateForFolder(); 46 | switch (cursorPos) { 47 | case 0: 48 | this->state = STATE_DO_SUBSTATE; 49 | this->subState = std::make_unique(this->wiiutitles, this->wiiuTitlesCount, true); 50 | break; 51 | case 1: 52 | this->state = STATE_DO_SUBSTATE; 53 | this->subState = std::make_unique(this->wiititles, this->vWiiTitlesCount, false); 54 | break; 55 | default: 56 | return SUBSTATE_RUNNING; 57 | } 58 | } 59 | if (input->get(TRIGGER, PAD_BUTTON_B)) 60 | return SUBSTATE_RETURN; 61 | if (input->get(TRIGGER, PAD_BUTTON_UP)) 62 | if (--cursorPos == -1) 63 | ++cursorPos; 64 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) 65 | if (++cursorPos == ENTRYCOUNT) 66 | --cursorPos; 67 | } else if (this->state == STATE_DO_SUBSTATE) { 68 | auto retSubState = this->subState->update(input); 69 | if (retSubState == SUBSTATE_RUNNING) { 70 | // keep running. 71 | return SUBSTATE_RUNNING; 72 | } else if (retSubState == SUBSTATE_RETURN) { 73 | this->subState.reset(); 74 | this->state = STATE_BATCH_RESTORE_MENU; 75 | } 76 | } 77 | return SUBSTATE_RUNNING; 78 | } -------------------------------------------------------------------------------- /src/menu/ConfigMenuState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | static int cursorPos = 0; 10 | #define ENTRYCOUNT 2 11 | 12 | static std::string language; 13 | extern bool firstSDWrite; 14 | 15 | void ConfigMenuState::render() { 16 | DrawUtils::setFontColor(COLOR_INFO); 17 | consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Configuration Options")); 18 | DrawUtils::setFontColor(COLOR_TEXT); 19 | language = LanguageUtils::getLoadedLanguage(); 20 | consolePrintPos(M_OFF, 2, LanguageUtils::gettext(" Language: %s"), language.c_str()); 21 | 22 | consolePrintPos(M_OFF, 4, LanguageUtils::gettext(" Always apply Backup Excludes: %s"), 23 | GlobalCfg::global->alwaysApplyExcludes ? LanguageUtils::gettext("Yes") : LanguageUtils::gettext("No")); 24 | 25 | DrawUtils::setFontColor(COLOR_INFO); 26 | consolePrintPos(M_OFF + 2, 8,LanguageUtils::gettext("WiiU Serial Id: %s"),Metadata::thisConsoleSerialId.c_str()); 27 | 28 | DrawUtils::setFontColor(COLOR_TEXT); 29 | consolePrintPos(M_OFF, 2 + cursorPos * 2, "\u2192"); 30 | consolePrintPosAligned(17,4,2,LanguageUtils::gettext("\ue045 SaveConfig \ue001: Back")); 31 | } 32 | 33 | ApplicationState::eSubState ConfigMenuState::update(Input *input) { 34 | if (input->get(TRIGGER, PAD_BUTTON_B)) 35 | return SUBSTATE_RETURN; 36 | if (input->get(TRIGGER, PAD_BUTTON_UP)) 37 | if (--cursorPos == -1) 38 | ++cursorPos; 39 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) 40 | if (++cursorPos == ENTRYCOUNT) 41 | --cursorPos; 42 | if (input->get(TRIGGER, PAD_BUTTON_RIGHT)) { 43 | switch (cursorPos) { 44 | case 0: 45 | if (language == LanguageUtils::gettext("Japanese")) 46 | LanguageUtils::loadLanguage(Swkbd_LanguageType__German); 47 | else if (language == LanguageUtils::gettext("German")) 48 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Italian); 49 | else if (language == LanguageUtils::gettext("Italian")) 50 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Portuguese); 51 | else if (language == LanguageUtils::gettext("Portuguese")) 52 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Spanish); 53 | else if (language == LanguageUtils::gettext("Spanish")) 54 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Chinese1); 55 | else if (language == LanguageUtils::gettext("Traditional Chinese")) 56 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Korean); 57 | else if (language == LanguageUtils::gettext("Korean")) 58 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Russian); 59 | else if (language == LanguageUtils::gettext("Russian")) 60 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Chinese2); 61 | else if (language == LanguageUtils::gettext("Simplified Chinese")) 62 | LanguageUtils::loadLanguage(Swkbd_LanguageType__English); 63 | else if (language == LanguageUtils::gettext("English")) 64 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Japanese); 65 | break; 66 | case 1: 67 | GlobalCfg::global->alwaysApplyExcludes = GlobalCfg::global->alwaysApplyExcludes ? false : true; 68 | break; 69 | } 70 | } 71 | if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { 72 | switch (cursorPos) { 73 | case 0: 74 | if (language == LanguageUtils::gettext("Japanese")) 75 | LanguageUtils::loadLanguage(Swkbd_LanguageType__English); 76 | else if (language == LanguageUtils::gettext("English")) 77 | LanguageUtils::loadLanguage(Swkbd_LanguageType__German); 78 | else if (language == LanguageUtils::gettext("German")) 79 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Chinese2); 80 | else if (language == LanguageUtils::gettext("Simplified Chinese")) 81 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Russian); 82 | else if (language == LanguageUtils::gettext("Russian")) 83 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Korean); 84 | else if (language == LanguageUtils::gettext("Korean")) 85 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Chinese1); 86 | else if (language == LanguageUtils::gettext("Traditional Chinese")) 87 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Spanish); 88 | else if (language == LanguageUtils::gettext("Spanish")) 89 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Portuguese); 90 | else if (language == LanguageUtils::gettext("Portuguese")) 91 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Italian); 92 | else if (language == LanguageUtils::gettext("Italian")) 93 | LanguageUtils::loadLanguage(Swkbd_LanguageType__Japanese); 94 | break; 95 | case 1: 96 | GlobalCfg::global->alwaysApplyExcludes = GlobalCfg::global->alwaysApplyExcludes ? false : true; 97 | break; 98 | } 99 | } 100 | if (input->get(TRIGGER, PAD_BUTTON_PLUS)) { 101 | if ( GlobalCfg::global->getConfig() ) { 102 | if (firstSDWrite) 103 | sdWriteDisclaimer(); 104 | if ( GlobalCfg::global->save() ) 105 | promptMessage(COLOR_BG_OK,LanguageUtils::gettext("Configuration saved")); 106 | else 107 | promptMessage(COLOR_BG_KO,LanguageUtils::gettext("Error saving configuration")); 108 | } 109 | else 110 | promptError(LanguageUtils::gettext("Error processing configuration")); 111 | } 112 | return SUBSTATE_RUNNING; 113 | } -------------------------------------------------------------------------------- /src/menu/KeyboardState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define KB_X_OFFSET 2 11 | #define KB_Y_OFFSET 3 12 | #define KB_ROW_OFFSET 6 13 | 14 | void KeyboardState::render() { 15 | DrawUtils::setFontColor(COLOR_INFO); 16 | consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Keyboard")); 17 | DrawUtils::setFontColor(COLOR_TEXT); 18 | if (this->state == STATE_KEYBOARD) { 19 | DrawUtils::setFontColor(COLOR_TEXT); 20 | consolePrintPosAligned(0,4,1,"Keyboard"); 21 | 22 | DrawUtils::setFontColor(COLOR_INFO); 23 | consolePrintPosAligned(3,0,1,("["+keyboard->input+"]").c_str()); 24 | DrawUtils::setFontColor(COLOR_TEXT); 25 | for (int row_=0;row_<4;row_++) 26 | for (int column_=0;column_getKeyboardRowSize(row_);column_++) { 27 | kConsolePrintPos(KB_X_OFFSET+column_,KB_Y_OFFSET+row_,KB_ROW_OFFSET*row_, "%s", keyboard->getKey(row_,column_).c_str()); 28 | DrawUtils::drawKey(KB_X_OFFSET+column_,KB_Y_OFFSET+row_,KB_ROW_OFFSET*row_,COLOR_WHITE); 29 | } 30 | DrawUtils::setFontColor(COLOR_KEY_S); 31 | kConsolePrintPos(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET-3,"%s", keyboard->getCurrentKey().c_str()); 32 | kConsolePrintPos(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET+3,"%s", keyboard->getCurrentKey().c_str()); 33 | DrawUtils::setFontColor(COLOR_KEY); 34 | kConsolePrintPos(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET,"%s", keyboard->getCurrentKey().c_str()); 35 | DrawUtils::drawKey(cursorPosX+KB_X_OFFSET,cursorPosY+KB_Y_OFFSET,cursorPosY*KB_ROW_OFFSET,COLOR_KEY_C); 36 | DrawUtils::setFontColor(COLOR_TEXT); 37 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Press Key \uE003: Shift \uE002: Del \ue045: OK! \ue001: Back")); 38 | } 39 | } 40 | 41 | ApplicationState::eSubState KeyboardState::update(Input *input) { 42 | if (input->get(TRIGGER, PAD_BUTTON_B)) { 43 | return SUBSTATE_RETURN; 44 | } 45 | if (input->get(TRIGGER, PAD_BUTTON_LEFT)) { 46 | cursorPosX = keyboard->kbLeft(); 47 | } 48 | if (input->get(TRIGGER, PAD_BUTTON_RIGHT)) { 49 | cursorPosX = keyboard->kbRight(); 50 | } 51 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { 52 | cursorPosY = keyboard->kbDown(); 53 | cursorPosX = keyboard->getColumn(); 54 | } 55 | if (input->get(TRIGGER, PAD_BUTTON_UP)) { 56 | cursorPosY = keyboard->kbUp(); 57 | cursorPosX = keyboard->getColumn(); 58 | } 59 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 60 | keyboard->kbKeyPressed(); 61 | } 62 | if (input->get(TRIGGER,PAD_BUTTON_X)) { 63 | keyboard->delPressed(); 64 | } 65 | if (input->get(TRIGGER,PAD_BUTTON_Y)) { 66 | keyboard->shiftPressed(); 67 | cursorPosX = keyboard->getColumn(); 68 | } 69 | if (input->get(TRIGGER,PAD_BUTTON_PLUS)) { 70 | this->input = keyboard->input; 71 | return SUBSTATE_RETURN; 72 | } 73 | return SUBSTATE_RUNNING; 74 | } -------------------------------------------------------------------------------- /src/menu/MainMenuState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | 16 | #define ENTRYCOUNT 5 17 | 18 | static int cursorPos = 0; 19 | 20 | void MainMenuState::render() { 21 | if (this->state == STATE_DO_SUBSTATE) { 22 | if (this->subState == nullptr) { 23 | OSFatal("SubState was null"); 24 | } 25 | this->subState->render(); 26 | return; 27 | } 28 | if (this->state == STATE_MAIN_MENU) { 29 | DrawUtils::setFontColor(COLOR_INFO); 30 | consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Main menu")); 31 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); 32 | consolePrintPos(M_OFF, 2, LanguageUtils::gettext(" Wii U Save Management (%u Title%s)"), this->wiiuTitlesCount, 33 | (this->wiiuTitlesCount > 1) ? "s" : ""); 34 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); 35 | consolePrintPos(M_OFF, 3, LanguageUtils::gettext(" vWii Save Management (%u Title%s)"), this->vWiiTitlesCount, 36 | (this->vWiiTitlesCount > 1) ? "s" : ""); 37 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); 38 | consolePrintPos(M_OFF, 4, LanguageUtils::gettext(" Batch Backup")); 39 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,3); 40 | consolePrintPos(M_OFF, 5, LanguageUtils::gettext(" Batch Restore")); 41 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,4); 42 | consolePrintPos(M_OFF, 6, LanguageUtils::gettext(" BackupSet Management")); 43 | DrawUtils::setFontColor(COLOR_TEXT); 44 | consolePrintPos(M_OFF, 2 + cursorPos, "\u2192"); 45 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\uE002: Options \ue000: Select Mode")); 46 | } 47 | } 48 | 49 | ApplicationState::eSubState MainMenuState::update(Input *input) { 50 | if (this->state == STATE_MAIN_MENU) { 51 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 52 | switch (cursorPos) { 53 | case 0: 54 | this->state = STATE_DO_SUBSTATE; 55 | this->subState = std::make_unique(this->wiiutitles, this->wiiuTitlesCount); 56 | break; 57 | case 1: 58 | this->state = STATE_DO_SUBSTATE; 59 | this->subState = std::make_unique(this->wiititles, this->vWiiTitlesCount); 60 | break; 61 | case 2: 62 | this->state = STATE_DO_SUBSTATE; 63 | this->subState = std::make_unique(this->wiiutitles, this->wiititles, this->wiiuTitlesCount, this->vWiiTitlesCount); 64 | break; 65 | case 3: 66 | this->state = STATE_DO_SUBSTATE; 67 | this->subState = std::make_unique(this->wiiutitles, this->wiititles, this->wiiuTitlesCount, this->vWiiTitlesCount); 68 | break; 69 | case 4: 70 | this->state = STATE_DO_SUBSTATE; 71 | this->substateCalled = STATE_BACKUPSET_MENU; 72 | this->subState = std::make_unique(); 73 | break; 74 | default: 75 | break; 76 | } 77 | } 78 | if (input->get(TRIGGER, PAD_BUTTON_X)) { 79 | this->state = STATE_DO_SUBSTATE; 80 | this->subState = std::make_unique(); 81 | } 82 | if (input->get(TRIGGER, PAD_BUTTON_UP)) 83 | if (--cursorPos == -1) 84 | ++cursorPos; 85 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) 86 | if (++cursorPos == ENTRYCOUNT) 87 | --cursorPos; 88 | } else if (this->state == STATE_DO_SUBSTATE) { 89 | auto retSubState = this->subState->update(input); 90 | if (retSubState == SUBSTATE_RUNNING) { 91 | // keep running. 92 | return SUBSTATE_RUNNING; 93 | } else if (retSubState == SUBSTATE_RETURN) { 94 | // if ( this->substateCalled == STATE_BACKUPSET_MENU) { 95 | // slot = 0; 96 | // getAccountsSD(&this->title, slot); 97 | // } 98 | this->subState.reset(); 99 | this->state = STATE_MAIN_MENU; 100 | } 101 | } 102 | return SUBSTATE_RUNNING; 103 | } -------------------------------------------------------------------------------- /src/menu/TitleTaskState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | static int cursorPos = 0; 13 | static int entrycount; 14 | static uint8_t slot = 0; 15 | static int8_t wiiuuser = -1, wiiuuser_d = -1, sduser = -1; 16 | static bool common = true; 17 | 18 | void TitleTaskState::render() { 19 | if (this->state == STATE_DO_SUBSTATE) { 20 | if (this->subState == nullptr) { 21 | OSFatal("SubState was null"); 22 | } 23 | this->subState->render(); 24 | return; 25 | } 26 | if (this->state == STATE_TITLE_TASKS) { 27 | DrawUtils::setFontColor(COLOR_INFO_AT_CURSOR); 28 | consolePrintPosAligned(0, 4, 2,LanguageUtils::gettext("WiiU Serial Id: %s"),Metadata::thisConsoleSerialId.c_str()); 29 | DrawUtils::setFontColor(COLOR_INFO); 30 | consolePrintPos(22,0,LanguageUtils::gettext("Tasks")); 31 | this->isWiiUTitle = (this->title.highID == 0x00050000) || (this->title.highID == 0x00050002); 32 | entrycount = 3 + 2 * static_cast(this->isWiiUTitle) + 1 * static_cast(this->isWiiUTitle && (this->title.isTitleDupe)); 33 | if (cursorPos > entrycount) 34 | cursorPos = 0; 35 | DrawUtils::setFontColor(COLOR_TEXT); 36 | consolePrintPos(M_OFF, 2, " [%08X-%08X] [%s]", this->title.highID, this->title.lowID, 37 | this->title.productCode); 38 | consolePrintPos(M_OFF, 3, " %s", this->title.shortName); 39 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,0); 40 | consolePrintPos(M_OFF, 5, LanguageUtils::gettext(" Backup savedata")); 41 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,1); 42 | consolePrintPos(M_OFF, 6, LanguageUtils::gettext(" Restore savedata")); 43 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,2); 44 | consolePrintPos(M_OFF, 7, LanguageUtils::gettext(" Wipe savedata")); 45 | if (this->isWiiUTitle) { 46 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,3); 47 | consolePrintPos(M_OFF, 8, LanguageUtils::gettext(" Import from loadiine")); 48 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,4); 49 | consolePrintPos(M_OFF, 9, LanguageUtils::gettext(" Export to loadiine")); 50 | if (this->title.isTitleDupe) { 51 | DrawUtils::setFontColorByCursor(COLOR_TEXT,COLOR_TEXT_AT_CURSOR,cursorPos,5); 52 | consolePrintPos(M_OFF, 10, LanguageUtils::gettext(" Copy Savedata to Title in %s"), 53 | this->title.isTitleOnUSB ? "NAND" : "USB"); 54 | } 55 | if (this->title.iconBuf != nullptr) 56 | DrawUtils::drawTGA(660, 80, 1, this->title.iconBuf); 57 | } else if (this->title.iconBuf != nullptr) 58 | DrawUtils::drawRGB5A3(645, 80, 1, this->title.iconBuf); 59 | DrawUtils::setFontColor(COLOR_TEXT); 60 | consolePrintPos(M_OFF, 2 + 3 + cursorPos, "\u2192"); 61 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select Task \ue001: Back")); 62 | } 63 | } 64 | 65 | ApplicationState::eSubState TitleTaskState::update(Input *input) { 66 | if (this->state == STATE_TITLE_TASKS) { 67 | if (input->get(TRIGGER, PAD_BUTTON_B)) 68 | return SUBSTATE_RETURN; 69 | 70 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 71 | bool noError = true; 72 | this->task = (Task) cursorPos; 73 | 74 | if (this->task == backup) { 75 | if (!this->title.saveInit) { 76 | promptError(LanguageUtils::gettext("No save to Backup.")); 77 | noError = false; 78 | } else 79 | BackupSetList::setBackupSetSubPathToRoot(); // from backup menu, always backup to root 80 | } 81 | 82 | if (this->task == restore) { 83 | BackupSetList::setBackupSetSubPath(); 84 | getAccountsSD(&this->title, slot); 85 | wiiuuser = ((sduser == -1) ? -1 : wiiuuser); 86 | sduser = ((wiiuuser == -1) ? -1 : sduser); 87 | } 88 | 89 | if (this->task == wipe) { 90 | if (!this->title.saveInit) { 91 | promptError(LanguageUtils::gettext("No save to Wipe.")); 92 | noError = false; 93 | } else 94 | BackupSetList::setBackupSetSubPathToRoot(); // default behaviour: unaware of backupsets 95 | } 96 | 97 | if ((this->task == importLoadiine) || (this->task == exportLoadiine)) { 98 | BackupSetList::setBackupSetSubPathToRoot(); // default behaviour: unaware of backupsets 99 | char gamePath[PATH_SIZE]; 100 | memset(versionList, 0, 0x100 * sizeof(int)); 101 | if (!getLoadiineGameSaveDir(gamePath, this->title.productCode, this->title.longName, this->title.highID, this->title.lowID)) { 102 | return SUBSTATE_RUNNING; 103 | } 104 | getLoadiineSaveVersionList(versionList, gamePath); 105 | if (this->task == importLoadiine) { 106 | importFromLoadiine(&this->title, common, versionList != nullptr ? versionList[slot] : 0); 107 | } 108 | if (this->task == exportLoadiine) { 109 | if (!this->title.saveInit) { 110 | promptError(LanguageUtils::gettext("No save to Export.")); 111 | noError = false; 112 | } 113 | exportToLoadiine(&this->title, common, versionList != nullptr ? versionList[slot] : 0); 114 | } 115 | } 116 | 117 | if (this->task == copytoOtherDevice) { 118 | if (!this->title.saveInit) { 119 | promptError(LanguageUtils::gettext("No save to Copy.")); 120 | noError = false; 121 | } else 122 | BackupSetList::setBackupSetSubPathToRoot(); // default behaviour: unaware of backupsets 123 | } 124 | if (noError) { 125 | DrawUtils::setRedraw(true); 126 | this->state = STATE_DO_SUBSTATE; 127 | this->subState = std::make_unique(this->title, this->task, this->versionList, sduser, wiiuuser, common, wiiuuser_d, this->titles, this->titlesCount); 128 | } 129 | } 130 | if (cursorPos > entrycount) 131 | cursorPos = entrycount; 132 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { 133 | if (entrycount <= 14) 134 | cursorPos = (cursorPos + 1) % entrycount; 135 | } else if (input->get(TRIGGER, PAD_BUTTON_UP)) { 136 | if (cursorPos > 0) 137 | --cursorPos; 138 | } 139 | } else if (this->state == STATE_DO_SUBSTATE) { 140 | auto retSubState = this->subState->update(input); 141 | if (retSubState == SUBSTATE_RUNNING) { 142 | // keep running. 143 | return SUBSTATE_RUNNING; 144 | } else if (retSubState == SUBSTATE_RETURN) { 145 | this->subState.reset(); 146 | this->state = STATE_TITLE_TASKS; 147 | } 148 | } 149 | return SUBSTATE_RUNNING; 150 | } -------------------------------------------------------------------------------- /src/menu/WiiUTitleListState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define MAX_TITLE_SHOW 14 12 | int WiiUTitleListState::cursorPos = 0; 13 | int WiiUTitleListState::scroll = 0; 14 | 15 | void WiiUTitleListState::render() { 16 | if (this->state == STATE_DO_SUBSTATE) { 17 | if (this->subState == nullptr) { 18 | OSFatal("SubState was null"); 19 | } 20 | this->subState->render(); 21 | return; 22 | } 23 | if (this->state == STATE_WIIU_TITLE_LIST) { 24 | if ((this->titles == nullptr) || (this->titlesCount == 0)) { 25 | promptError(LanguageUtils::gettext("No Wii U titles found.")); 26 | this->noTitles = true; 27 | DrawUtils::beginDraw(); 28 | consolePrintPosAligned(8, 4, 1, LanguageUtils::gettext("No Wii U titles found")); 29 | consolePrintPosAligned(17, 4, 1, LanguageUtils::gettext("Any Button: Back")); 30 | return; 31 | } 32 | DrawUtils::setFontColor(COLOR_INFO); 33 | consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("Wii U Titles")); 34 | DrawUtils::setFontColor(COLOR_TEXT); 35 | consolePrintPosAligned(0 , 4, 2, LanguageUtils::gettext("%s Sort: %s \ue084"), 36 | (this->titleSort > 0) ? (this->sortAscending ? "\ue083 \u2193" : "\ue083 \u2191") : "", this->sortNames[this->titleSort]); 37 | for (int i = 0; i < MAX_TITLE_SHOW; i++) { 38 | if (i + this->scroll < 0 || i + this->scroll >= this->titlesCount) 39 | break; 40 | 41 | DrawUtils::setFontColorByCursor(COLOR_LIST,COLOR_LIST_AT_CURSOR,cursorPos,i); 42 | if (!this->titles[i + this->scroll].saveInit) 43 | DrawUtils::setFontColorByCursor(COLOR_LIST_NOSAVE,COLOR_LIST_NOSAVE_AT_CURSOR,cursorPos,i); 44 | if (strcmp(this->titles[i + this->scroll].shortName, "DONT TOUCH ME") == 0) 45 | DrawUtils::setFontColorByCursor(COLOR_LIST_DANGER,COLOR_LIST_DANGER_AT_CURSOR,cursorPos,i); 46 | 47 | consolePrintPos(M_OFF+1, i + 2, " %s %s%s%s%s", 48 | this->titles[i + this->scroll].shortName, 49 | this->titles[i + this->scroll].isTitleOnUSB ? "(USB)" : "(NAND)", 50 | this->titles[i + this->scroll].isTitleDupe ? " [D]" : "", 51 | this->titles[i + this->scroll].noFwImg ? LanguageUtils::gettext(" [vWiiInject]") : "", 52 | this->titles[i + this->scroll].saveInit ? "" : LanguageUtils::gettext(" [Not Init]") 53 | ); 54 | if (this->titles[i + this->scroll].iconBuf != nullptr) { 55 | DrawUtils::drawTGA((M_OFF + 4) * 12 - 2, (i + 3) * 24, 0.18, this->titles[i + this->scroll].iconBuf); 56 | } 57 | } 58 | DrawUtils::setFontColor(COLOR_TEXT); 59 | consolePrintPos(-1, 2 + cursorPos, "\u2192"); 60 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select Game \ue001: Back")); 61 | } 62 | } 63 | 64 | ApplicationState::eSubState WiiUTitleListState::update(Input *input) { 65 | if (this->state == STATE_WIIU_TITLE_LIST) { 66 | if (input->get(TRIGGER, PAD_BUTTON_B) || noTitles) 67 | return SUBSTATE_RETURN; 68 | if (input->get(TRIGGER, PAD_BUTTON_R)) { 69 | this->titleSort = (this->titleSort + 1) % 4; 70 | sortTitle(this->titles, this->titles + this->titlesCount, this->titleSort, this->sortAscending); 71 | } 72 | if (input->get(TRIGGER, PAD_BUTTON_L)) { 73 | if (this->titleSort > 0) { 74 | this->sortAscending = !this->sortAscending; 75 | sortTitle(this->titles, this->titles + this->titlesCount, this->titleSort, this->sortAscending); 76 | } 77 | } 78 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 79 | this->targ = cursorPos + this->scroll; 80 | if (this->titles[this->targ].highID == 0 || this->titles[this->targ].lowID == 0) 81 | return SUBSTATE_RUNNING; 82 | if (strcmp(this->titles[this->targ].shortName, "DONT TOUCH ME") == 0) { 83 | if (!promptConfirm(ST_ERROR, LanguageUtils::gettext("CBHC save. Could be dangerous to modify. Continue?")) || 84 | !promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you REALLY sure?"))) { 85 | return SUBSTATE_RUNNING; 86 | } 87 | } 88 | /* 89 | std::string path = StringUtils::stringFormat("%s/usr/title/000%x/%x/code/fw.img", 90 | (this->titles[this->targ].isTitleOnUSB) ? getUSB().c_str() : "storage_mlc01:", this->titles[this->targ].highID, 91 | this->titles[this->targ].lowID); 92 | if (checkEntry(path.c_str()) != 0) 93 | */ 94 | if(this->titles[this->targ].noFwImg) 95 | if (!promptConfirm(ST_ERROR, LanguageUtils::gettext("vWii saves are in the vWii section. Continue?"))) 96 | return SUBSTATE_RUNNING; 97 | 98 | 99 | if (!this->titles[this->targ].saveInit) { 100 | if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Recommended to run Game at least one time. Continue?")) || 101 | !promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you REALLY sure?"))) { 102 | return SUBSTATE_RUNNING; 103 | } 104 | } 105 | DrawUtils::setRedraw(true); 106 | this->state = STATE_DO_SUBSTATE; 107 | this->subState = std::make_unique(this->titles[this->targ], this->titles, this->titlesCount); 108 | } 109 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { 110 | if (this->titlesCount <= 14) 111 | cursorPos = (cursorPos + 1) % this->titlesCount; 112 | else if (cursorPos < 6) 113 | cursorPos++; 114 | else if (((cursorPos + this->scroll + 1) % this->titlesCount) != 0) 115 | scroll++; 116 | else 117 | cursorPos = scroll = 0; 118 | } else if (input->get(TRIGGER, PAD_BUTTON_UP)) { 119 | if (scroll > 0) 120 | cursorPos -= (cursorPos > 6) ? 1 : 0 * (scroll--); 121 | else if (cursorPos > 0) 122 | cursorPos--; 123 | else if (this->titlesCount > 14) 124 | scroll = this->titlesCount - (cursorPos = 6) - 1; 125 | else 126 | cursorPos = this->titlesCount - 1; 127 | } 128 | } else if (this->state == STATE_DO_SUBSTATE) { 129 | auto retSubState = this->subState->update(input); 130 | if (retSubState == SUBSTATE_RUNNING) { 131 | // keep running. 132 | return SUBSTATE_RUNNING; 133 | } else if (retSubState == SUBSTATE_RETURN) { 134 | this->subState.reset(); 135 | this->state = STATE_WIIU_TITLE_LIST; 136 | } 137 | } 138 | return SUBSTATE_RUNNING; 139 | } -------------------------------------------------------------------------------- /src/menu/vWiiTitleListState.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #define MAX_TITLE_SHOW 14 11 | int vWiiTitleListState::scroll = 0; 12 | int vWiiTitleListState::cursorPos = 0; 13 | 14 | void vWiiTitleListState::render() { 15 | if (this->state == STATE_DO_SUBSTATE) { 16 | if (this->subState == nullptr) { 17 | OSFatal("SubState was null"); 18 | } 19 | this->subState->render(); 20 | return; 21 | } 22 | if (this->state == STATE_VWII_TITLE_LIST) { 23 | if ((this->titles == nullptr) || (this->titlesCount == 0)) { 24 | promptError(LanguageUtils::gettext("No vWii titles found.")); 25 | this->noTitles = true; 26 | DrawUtils::beginDraw(); 27 | consolePrintPosAligned(8, 4, 1, LanguageUtils::gettext("No vWii titles found.")); 28 | consolePrintPosAligned(17, 4, 1, LanguageUtils::gettext("Any Button: Back")); 29 | return; 30 | } 31 | DrawUtils::setFontColor(COLOR_INFO); 32 | consolePrintPosAligned(0, 4, 1,LanguageUtils::gettext("vWii Titles")); 33 | DrawUtils::setFontColor(COLOR_TEXT); 34 | consolePrintPosAligned(0, 4, 2, LanguageUtils::gettext("%s Sort: %s \ue084"), 35 | (titleSort > 0) ? (sortAscending ? "\ue083 \u2193" : "\ue083 \u2191") : "", this->sortNames[this->titleSort]); 36 | for (int i = 0; i < 14; i++) { 37 | if (i + this->scroll < 0 || i + this->scroll >= this->titlesCount) 38 | break; 39 | 40 | DrawUtils::setFontColorByCursor(COLOR_LIST,COLOR_LIST_AT_CURSOR,cursorPos,i); 41 | if (!this->titles[i + this->scroll].saveInit) 42 | DrawUtils::setFontColorByCursor(COLOR_LIST_NOSAVE,COLOR_LIST_NOSAVE_AT_CURSOR,cursorPos,i); 43 | if (strcmp(this->titles[i + this->scroll].shortName, "DONT TOUCH ME") == 0) 44 | DrawUtils::setFontColorByCursor(COLOR_LIST_DANGER,COLOR_LIST_DANGER_AT_CURSOR,cursorPos,i); 45 | 46 | consolePrintPos(M_OFF + 1, i + 2, " %s %s%s", titles[i + this->scroll].shortName, 47 | titles[i + this->scroll].isTitleDupe ? " [D]" : "", 48 | titles[i + this->scroll].saveInit ? "" : LanguageUtils::gettext(" [Not Init]")); 49 | if (titles[i + this->scroll].iconBuf != nullptr) { 50 | DrawUtils::drawRGB5A3((M_OFF + 2) * 12 - 2, (i + 3) * 24 + 3, 0.25, 51 | titles[i + this->scroll].iconBuf); 52 | } 53 | } 54 | DrawUtils::setFontColor(COLOR_TEXT); 55 | consolePrintPos(-3, 2 + cursorPos, "\u2192"); 56 | consolePrintPosAligned(17, 4, 2, LanguageUtils::gettext("\ue000: Select Game \ue001: Back")); 57 | } 58 | } 59 | 60 | ApplicationState::eSubState vWiiTitleListState::update(Input *input) { 61 | if (this->state == STATE_VWII_TITLE_LIST) { 62 | if (input->get(TRIGGER, PAD_BUTTON_B) || noTitles) 63 | return SUBSTATE_RETURN; 64 | if (input->get(TRIGGER, PAD_BUTTON_R)) { 65 | this->titleSort = (this->titleSort + 1) % 4; 66 | sortTitle(this->titles, this->titles + this->titlesCount, this->titleSort, this->sortAscending); 67 | } 68 | if (input->get(TRIGGER, PAD_BUTTON_L)) { 69 | if (this->titleSort > 0) { 70 | this->sortAscending = !this->sortAscending; 71 | sortTitle(this->titles, this->titles + this->titlesCount, this->titleSort, this->sortAscending); 72 | } 73 | } 74 | if (input->get(TRIGGER, PAD_BUTTON_A)) { 75 | this->targ = cursorPos + this->scroll; 76 | if (this->titles[this->targ].highID == 0 || this->titles[this->targ].lowID == 0) 77 | return SUBSTATE_RUNNING; 78 | if (!this->titles[this->targ].saveInit) { 79 | if (!promptConfirm(ST_WARNING, LanguageUtils::gettext("Recommended to run Game at least one time. Continue?")) || 80 | !promptConfirm(ST_WARNING, LanguageUtils::gettext("Are you REALLY sure?"))) { 81 | return SUBSTATE_RUNNING; 82 | } 83 | } 84 | DrawUtils::setRedraw(true); 85 | this->state = STATE_DO_SUBSTATE; 86 | this->subState = std::make_unique(this->titles[this->targ], this->titles, this->titlesCount); 87 | } 88 | if (input->get(TRIGGER, PAD_BUTTON_DOWN)) { 89 | if (this->titlesCount <= 14) 90 | cursorPos = (cursorPos + 1) % this->titlesCount; 91 | else if (cursorPos < 6) 92 | cursorPos++; 93 | else if (((cursorPos + this->scroll + 1) % this->titlesCount) != 0) 94 | scroll++; 95 | else 96 | cursorPos = scroll = 0; 97 | } else if (input->get(TRIGGER, PAD_BUTTON_UP)) { 98 | if (scroll > 0) 99 | cursorPos -= (cursorPos > 6) ? 1 : 0 * (scroll--); 100 | else if (cursorPos > 0) 101 | cursorPos--; 102 | else if (this->titlesCount > 14) 103 | scroll = this->titlesCount - (cursorPos = 6) - 1; 104 | else 105 | cursorPos = this->titlesCount - 1; 106 | } 107 | } else if (this->state == STATE_DO_SUBSTATE) { 108 | auto retSubState = this->subState->update(input); 109 | if (retSubState == SUBSTATE_RUNNING) { 110 | // keep running. 111 | return SUBSTATE_RUNNING; 112 | } else if (retSubState == SUBSTATE_RETURN) { 113 | this->subState.reset(); 114 | this->state = STATE_VWII_TITLE_LIST; 115 | } 116 | } 117 | return SUBSTATE_RUNNING; 118 | } -------------------------------------------------------------------------------- /src/utils/InputUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void Input::read() { 4 | VPADRead(VPAD_CHAN_0, &vpad_status, 1, nullptr); 5 | KPADRead(WPAD_CHAN_0, &kpad_status, 1); 6 | } 7 | 8 | bool Input::get(ButtonState state, Button button) const { 9 | uint32_t vpadState = 0; 10 | uint32_t kpadCoreState = 0; 11 | uint32_t kpadClassicState = 0; 12 | uint32_t kpadNunchukState = 0; 13 | uint32_t kpadProState = 0; 14 | 15 | auto examine = [state](const auto& status) -> uint32_t 16 | { 17 | switch (state) { 18 | case TRIGGER: 19 | return status.trigger; 20 | case HOLD: 21 | return status.hold; 22 | case RELEASE: 23 | return status.release; 24 | default: 25 | return 0; 26 | } 27 | }; 28 | 29 | if (!vpad_status.error) 30 | vpadState = examine(vpad_status); 31 | 32 | if (!kpad_status.error) { 33 | switch (kpad_status.extensionType) { 34 | case WPAD_EXT_CORE: 35 | kpadCoreState = examine(kpad_status); 36 | break; 37 | case WPAD_EXT_NUNCHUK: 38 | kpadCoreState = examine(kpad_status); 39 | kpadNunchukState = examine(kpad_status.nunchuk); 40 | break; 41 | case WPAD_EXT_CLASSIC: 42 | kpadCoreState = examine(kpad_status); 43 | kpadClassicState = examine(kpad_status.classic); 44 | break; 45 | case WPAD_EXT_PRO_CONTROLLER: 46 | kpadProState = examine(kpad_status.pro); 47 | break; 48 | } 49 | } 50 | 51 | if (!vpadState && 52 | !kpadCoreState && 53 | !kpadClassicState && 54 | !kpadNunchukState && 55 | !kpadProState) 56 | return false; 57 | 58 | switch (button) { 59 | case PAD_BUTTON_A: 60 | if (vpadState & VPAD_BUTTON_A) return true; 61 | if (kpadCoreState & WPAD_BUTTON_A) return true; 62 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_A) return true; 63 | if (kpadProState & WPAD_PRO_BUTTON_A) return true; 64 | break; 65 | case PAD_BUTTON_B: 66 | if (vpadState & VPAD_BUTTON_B) return true; 67 | if (kpadCoreState & WPAD_BUTTON_B) return true; 68 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_B) return true; 69 | if (kpadProState & WPAD_PRO_BUTTON_B) return true; 70 | break; 71 | case PAD_BUTTON_X: 72 | if (vpadState & VPAD_BUTTON_X) return true; 73 | if (kpadCoreState & WPAD_BUTTON_1) return true; 74 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_X) return true; 75 | if (kpadProState & WPAD_PRO_BUTTON_X) return true; 76 | break; 77 | case PAD_BUTTON_Y: 78 | if (vpadState & VPAD_BUTTON_Y) return true; 79 | if (kpadCoreState & WPAD_BUTTON_2) return true; 80 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_Y) return true; 81 | if (kpadProState & WPAD_PRO_BUTTON_Y) return true; 82 | break; 83 | case PAD_BUTTON_UP: 84 | if (vpadState & VPAD_BUTTON_UP) return true; 85 | if (vpadState & VPAD_STICK_L_EMULATION_UP) return true; 86 | if (kpadCoreState & WPAD_BUTTON_UP) return true; 87 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_UP) return true; 88 | if (kpadClassicState & WPAD_CLASSIC_STICK_L_EMULATION_UP) return true; 89 | if (kpadNunchukState & WPAD_NUNCHUK_STICK_EMULATION_UP) return true; 90 | if (kpadProState & WPAD_PRO_BUTTON_UP) return true; 91 | if (kpadProState & WPAD_PRO_STICK_L_EMULATION_UP) return true; 92 | break; 93 | case PAD_BUTTON_DOWN: 94 | if (vpadState & VPAD_BUTTON_DOWN) return true; 95 | if (vpadState & VPAD_STICK_L_EMULATION_DOWN) return true; 96 | if (kpadCoreState & WPAD_BUTTON_DOWN) return true; 97 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_DOWN) return true; 98 | if (kpadClassicState & WPAD_CLASSIC_STICK_L_EMULATION_DOWN) return true; 99 | if (kpadNunchukState & WPAD_NUNCHUK_STICK_EMULATION_DOWN) return true; 100 | if (kpadProState & WPAD_PRO_BUTTON_DOWN) return true; 101 | if (kpadProState & WPAD_PRO_STICK_L_EMULATION_DOWN) return true; 102 | break; 103 | case PAD_BUTTON_LEFT: 104 | if (vpadState & VPAD_BUTTON_LEFT) return true; 105 | if (vpadState & VPAD_STICK_L_EMULATION_LEFT) return true; 106 | if (kpadCoreState & WPAD_BUTTON_LEFT) return true; 107 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_LEFT) return true; 108 | if (kpadClassicState & WPAD_CLASSIC_STICK_L_EMULATION_LEFT) return true; 109 | if (kpadNunchukState & WPAD_NUNCHUK_STICK_EMULATION_LEFT) return true; 110 | if (kpadProState & WPAD_PRO_BUTTON_LEFT) return true; 111 | if (kpadProState & WPAD_PRO_STICK_L_EMULATION_LEFT) return true; 112 | break; 113 | case PAD_BUTTON_RIGHT: 114 | if (vpadState & VPAD_BUTTON_RIGHT) return true; 115 | if (vpadState & VPAD_STICK_L_EMULATION_RIGHT) return true; 116 | if (kpadCoreState & WPAD_BUTTON_RIGHT) return true; 117 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_RIGHT) return true; 118 | if (kpadClassicState & WPAD_CLASSIC_STICK_L_EMULATION_RIGHT) return true; 119 | if (kpadNunchukState & WPAD_NUNCHUK_STICK_EMULATION_RIGHT) return true; 120 | if (kpadProState & WPAD_PRO_BUTTON_RIGHT) return true; 121 | if (kpadProState & WPAD_PRO_STICK_L_EMULATION_RIGHT) return true; 122 | break; 123 | case PAD_BUTTON_L: 124 | if (vpadState & VPAD_BUTTON_L) return true; 125 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_L) return true; 126 | if (kpadProState & WPAD_PRO_BUTTON_L) return true; 127 | break; 128 | case PAD_BUTTON_R: 129 | if (vpadState & VPAD_BUTTON_R) return true; 130 | if (kpadCoreState & WPAD_BUTTON_PLUS) return true; 131 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_R) return true; 132 | if (kpadProState & WPAD_PRO_BUTTON_R) return true; 133 | break; 134 | case PAD_BUTTON_PLUS: 135 | if (vpadState & VPAD_BUTTON_PLUS) return true; 136 | if (kpadCoreState & WPAD_BUTTON_PLUS) return true; 137 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_PLUS) return true; 138 | if (kpadProState & WPAD_PRO_BUTTON_PLUS) return true; 139 | break; 140 | case PAD_BUTTON_MINUS: 141 | if (vpadState & VPAD_BUTTON_MINUS) return true; 142 | if (kpadCoreState & WPAD_BUTTON_MINUS) return true; 143 | if (kpadClassicState & WPAD_CLASSIC_BUTTON_MINUS) return true; 144 | if (kpadProState & WPAD_PRO_BUTTON_MINUS) return true; 145 | break; 146 | case PAD_BUTTON_ANY: 147 | return vpadState 148 | || kpadCoreState 149 | || kpadClassicState 150 | || kpadNunchukState 151 | || kpadProState; 152 | } 153 | 154 | return false; 155 | } 156 | -------------------------------------------------------------------------------- /src/utils/KeyboardUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_INPUT_SIZE 30 7 | 8 | void Keyboard::render() { 9 | } 10 | 11 | std::string Keyboard::ucs4ToUtf8(const std::u32string& in) 12 | { 13 | std::wstring_convert, char32_t> conv; 14 | return conv.to_bytes(in); 15 | } 16 | 17 | std::u32string Keyboard::utf8ToUcs4(const std::string& in) 18 | { 19 | std::wstring_convert, char32_t> conv; 20 | return conv.from_bytes(in); 21 | } 22 | 23 | int Keyboard::kbLeft() { 24 | if (column > 0) 25 | column--; 26 | else 27 | column = getKeyboardRowSize(row)-1; 28 | setCurrentKey(); 29 | return column; 30 | } 31 | 32 | int Keyboard::kbRight() { 33 | if ( column < getKeyboardRowSize(row)-1) 34 | column++; 35 | else 36 | column = 0; 37 | setCurrentKey(); 38 | return column; 39 | } 40 | 41 | int Keyboard::kbUp() { 42 | if ( row > 0 ) 43 | row--; 44 | else 45 | row = (int) currentKeyboard.size()-1; 46 | if (column > getKeyboardRowSize(row)-1) 47 | column = getKeyboardRowSize(row)-1; 48 | setCurrentKey(); 49 | return row; 50 | } 51 | 52 | int Keyboard::kbDown() { 53 | if ( row < (int) currentKeyboard.size()-1 ) 54 | row++; 55 | else 56 | row = 0; 57 | if (column > getKeyboardRowSize(row)-1) 58 | column = getKeyboardRowSize(row)-1; 59 | setCurrentKey(); 60 | return row; 61 | } 62 | 63 | void Keyboard::shiftPressed() { 64 | currentKeyboard = ( currentKeyboard == keysNormal ? keysShift : keysNormal ); 65 | if (column > getKeyboardRowSize(row)-1) 66 | column = getKeyboardRowSize(row)-1; 67 | setCurrentKey(); 68 | } 69 | 70 | void Keyboard::kbKeyPressed() { 71 | if (input.size() < MAX_INPUT_SIZE ) 72 | input.append(ucs4ToUtf8(currentKey)); 73 | } 74 | 75 | void Keyboard::delPressed() { 76 | if (input.size() > 0) 77 | input.pop_back(); 78 | } 79 | 80 | void Keyboard::setCurrentKey() { 81 | currentKey = currentKeyboard[row].substr(column,1); 82 | } 83 | 84 | std::string Keyboard::getKey(int row_,int column_) { 85 | return ucs4ToUtf8(currentKeyboard[row_].substr(column_,1)); 86 | } 87 | 88 | std::string Keyboard::getCurrentKey() { 89 | return ucs4ToUtf8(currentKeyboard[row].substr(column,1)); 90 | } 91 | 92 | int Keyboard::getKeyboardRowSize(int row_) { 93 | return currentKeyboard[row_].size(); 94 | } -------------------------------------------------------------------------------- /src/utils/LanguageUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | MSG *LanguageUtils::baseMSG = nullptr; 8 | 9 | Swkbd_LanguageType LanguageUtils::sysLang; 10 | Swkbd_LanguageType LanguageUtils::loadedLang; 11 | 12 | void LanguageUtils::loadLanguage(Swkbd_LanguageType language) { 13 | loadedLang = language; 14 | switch (language) { 15 | case Swkbd_LanguageType__Japanese: 16 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 17 | gettextLoadLanguage("romfs:/languages/japanese.json"); 18 | break; 19 | case Swkbd_LanguageType__English: 20 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 21 | gettextLoadLanguage("romfs:/languages/english.json"); 22 | break; 23 | /*case Swkbd_LanguageType__French: 24 | gettextLoadLanguage("romfs:/languages/french.json"); 25 | break; 26 | */ 27 | case Swkbd_LanguageType__German: 28 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 29 | gettextLoadLanguage("romfs:/languages/german.json"); 30 | break; 31 | case Swkbd_LanguageType__Italian: 32 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 33 | gettextLoadLanguage("romfs:/languages/italian.json"); 34 | break; 35 | case Swkbd_LanguageType__Spanish: 36 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 37 | gettextLoadLanguage("romfs:/languages/spanish.json"); 38 | break; 39 | case Swkbd_LanguageType__Chinese1: 40 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_CHINESE); 41 | gettextLoadLanguage("romfs:/languages/TChinese.json"); 42 | break; 43 | case Swkbd_LanguageType__Korean: 44 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_KOREAN); 45 | gettextLoadLanguage("romfs:/languages/korean.json"); 46 | break; 47 | /* 48 | case Swkbd_LanguageType__Dutch: 49 | gettextLoadLanguage("romfs:/languages/dutch.json"); 50 | break; 51 | */ 52 | case Swkbd_LanguageType__Portuguese: 53 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 54 | gettextLoadLanguage("romfs:/languages/portuguese.json"); 55 | break; 56 | case Swkbd_LanguageType__Russian: 57 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 58 | gettextLoadLanguage("romfs:/languages/russian.json"); 59 | break; 60 | case Swkbd_LanguageType__Chinese2: 61 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_CHINESE); 62 | gettextLoadLanguage("romfs:/languages/SChinese.json"); 63 | break; 64 | default: 65 | DrawUtils::setFont(OS_SHAREDDATATYPE_FONT_STANDARD); 66 | gettextLoadLanguage("romfs:/languages/english.json"); 67 | break; 68 | } 69 | } 70 | 71 | std::string LanguageUtils::getLoadedLanguage() { 72 | switch (loadedLang) { 73 | case Swkbd_LanguageType__Japanese: 74 | return gettext("Japanese"); 75 | case Swkbd_LanguageType__English: 76 | return gettext("English"); 77 | /*case Swkbd_LanguageType__French: 78 | return gettext("French"); 79 | */ 80 | case Swkbd_LanguageType__German: 81 | return gettext("German"); 82 | case Swkbd_LanguageType__Italian: 83 | return gettext("Italian"); 84 | case Swkbd_LanguageType__Spanish: 85 | return gettext("Spanish"); 86 | case Swkbd_LanguageType__Chinese1: 87 | return gettext("Traditional Chinese"); 88 | case Swkbd_LanguageType__Korean: 89 | return gettext("Korean"); 90 | /* 91 | case Swkbd_LanguageType__Dutch: 92 | return gettext("Dutch"); 93 | */ 94 | case Swkbd_LanguageType__Portuguese: 95 | return gettext("Portuguese"); 96 | case Swkbd_LanguageType__Russian: 97 | return gettext("Russian"); 98 | case Swkbd_LanguageType__Chinese2: 99 | return gettext("Simplified Chinese"); 100 | default: 101 | return gettext("English"); 102 | } 103 | } 104 | 105 | Swkbd_LanguageType LanguageUtils::getSystemLanguage() { 106 | UCHandle handle = UCOpen(); 107 | if (handle < 1) 108 | sysLang = Swkbd_LanguageType__English; 109 | 110 | auto *settings = (UCSysConfig *) MEMAllocFromDefaultHeapEx(sizeof(UCSysConfig), 0x40); 111 | if (settings == nullptr) { 112 | UCClose(handle); 113 | sysLang = Swkbd_LanguageType__English; 114 | } 115 | 116 | strcpy(settings->name, "cafe.language"); 117 | settings->access = 0; 118 | settings->dataType = UC_DATATYPE_UNSIGNED_INT; 119 | settings->error = UC_ERROR_OK; 120 | settings->dataSize = sizeof(Swkbd_LanguageType); 121 | settings->data = &sysLang; 122 | 123 | UCError err = UCReadSysConfig(handle, 1, settings); 124 | UCClose(handle); 125 | MEMFreeToDefaultHeap(settings); 126 | if (err != UC_ERROR_OK) 127 | sysLang = Swkbd_LanguageType__English; 128 | return sysLang; 129 | } 130 | 131 | // Hashing function from https://stackoverflow.com/a/2351171 132 | uint32_t LanguageUtils::hash_string(const char *str_param) { 133 | uint32_t hash = 0; 134 | 135 | while (*str_param != '\0') 136 | hash = hashMultiplier * hash + *str_param++; 137 | 138 | return hash; 139 | } 140 | 141 | MSG *LanguageUtils::findMSG(uint32_t id) { 142 | for (MSG *msg = baseMSG; msg; msg = msg->next) 143 | if (msg->id == id) 144 | return msg; 145 | 146 | return nullptr; 147 | } 148 | 149 | void LanguageUtils::setMSG(const char *msgid, const char *msgstr) { 150 | if (!msgstr) 151 | return; 152 | 153 | uint32_t id = hash_string(msgid); 154 | MSG *msg = (MSG *) MEMAllocFromDefaultHeap(sizeof(MSG)); 155 | msg->id = id; 156 | msg->msgstr = strdup(msgstr); 157 | msg->next = baseMSG; 158 | baseMSG = msg; 159 | } 160 | 161 | void LanguageUtils::gettextCleanUp() { 162 | while (baseMSG) { 163 | MSG *nextMsg = baseMSG->next; 164 | MEMFreeToDefaultHeap((void *) (baseMSG->msgstr)); 165 | MEMFreeToDefaultHeap(baseMSG); 166 | baseMSG = nextMsg; 167 | } 168 | } 169 | 170 | bool LanguageUtils::gettextLoadLanguage(const char *langFile) { 171 | uint8_t *buffer; 172 | int32_t size = loadFile(langFile, &buffer); 173 | if (buffer == nullptr) 174 | return false; 175 | 176 | bool ret = true; 177 | json_t *json = json_loadb((const char *) buffer, size, 0, nullptr); 178 | if (json) { 179 | size = json_object_size(json); 180 | if (size != 0) { 181 | const char *key; 182 | json_t *value; 183 | json_object_foreach(json, key, value) if (json_is_string(value)) 184 | setMSG(key, json_string_value(value)); 185 | } else { 186 | ret = false; 187 | } 188 | 189 | json_decref(json); 190 | } else { 191 | ret = false; 192 | } 193 | 194 | MEMFreeToDefaultHeap(buffer); 195 | return ret; 196 | } 197 | 198 | const char *LanguageUtils::gettext(const char *msgid) { 199 | MSG *msg = findMSG(hash_string(msgid)); 200 | return msg ? msg->msgstr : msgid; 201 | } 202 | -------------------------------------------------------------------------------- /src/utils/StateUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | 12 | bool State::aroma = false; 13 | 14 | void State::init() { 15 | OSDynLoad_Module mod; 16 | aroma = OSDynLoad_Acquire("homebrew_kernel", &mod) == OS_DYNLOAD_OK; 17 | if (aroma) { 18 | OSDynLoad_Release(mod); 19 | ProcUIInit(&OSSavesDone_ReadyToRelease); 20 | OSEnableHomeButtonMenu(true); 21 | } else 22 | WHBProcInit(); 23 | } 24 | 25 | uint32_t 26 | State::ConsoleProcCallbackAcquired(void *context) 27 | { 28 | return DrawUtils::initScreen(); 29 | } 30 | 31 | uint32_t 32 | State::ConsoleProcCallbackReleased(void *context) 33 | { 34 | return DrawUtils::deinitScreen(); 35 | } 36 | 37 | void State::registerProcUICallbacks() { 38 | if (aroma) { 39 | ProcUIRegisterCallback(PROCUI_CALLBACK_ACQUIRE, ConsoleProcCallbackAcquired, NULL, 100); 40 | ProcUIRegisterCallback(PROCUI_CALLBACK_RELEASE, ConsoleProcCallbackReleased, NULL, 100); 41 | } 42 | } 43 | 44 | bool State::AppRunning() { 45 | if (aroma) { 46 | bool app = true; 47 | if (OSIsMainCore()) { 48 | switch (ProcUIProcessMessages(true)) { 49 | case PROCUI_STATUS_EXITING: 50 | // Being closed, prepare to exit 51 | app = false; 52 | break; 53 | case PROCUI_STATUS_RELEASE_FOREGROUND: 54 | // Free up MEM1 to next foreground app, deinit screen, etc. 55 | ProcUIDrawDoneRelease(); 56 | break; 57 | case PROCUI_STATUS_IN_FOREGROUND: 58 | // Executed while app is in foreground 59 | app = true; 60 | break; 61 | case PROCUI_STATUS_IN_BACKGROUND: 62 | OSSleepTicks(OSMillisecondsToTicks(20)); 63 | break; 64 | } 65 | } 66 | 67 | return app; 68 | } 69 | return WHBProcIsRunning(); 70 | } 71 | 72 | void State::shutdown() { 73 | if (!aroma) 74 | WHBProcShutdown(); 75 | ProcUIShutdown(); 76 | } 77 | 78 | 79 | -------------------------------------------------------------------------------- /src/utils/StringUtils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool StringUtils::replace(std::string &str, const std::string &from, const std::string &to) { 4 | size_t start_pos = str.find(from); 5 | if (start_pos == std::string::npos) 6 | return false; 7 | str.replace(start_pos, from.length(), to); 8 | return true; 9 | } 10 | 11 | std::string StringUtils::decodeXMLEscapeLine(std::string xmlString) { 12 | replace(xmlString, """, "\""); 13 | replace(xmlString, "'", "'"); 14 | replace(xmlString, "<", "<"); 15 | replace(xmlString, ">", ">"); 16 | replace(xmlString, "&", "&"); 17 | return xmlString; 18 | } --------------------------------------------------------------------------------